Browse Source

Merge pull request 'Refactoring Shields Choices and Scheduler' (#48) from shield_refactoring into main

Reviewed-on: https://git.pranger.xyz/TEMPEST/tempest-devel/pulls/48
main
Stefan Pranger 4 years ago
parent
commit
037343ba97
  1. 8
      resources/examples/testfiles/shields/mdp-shields/dieSelectionPostSafetylambda07Pmin.shield
  2. 2
      resources/examples/testfiles/shields/mdp-shields/dieSelectionPreSafetygamma08Pmin.shield
  3. 7
      resources/examples/testfiles/shields/mdp-shields/dieSelectionPreSafetylambda08Pmin.shield
  4. 3
      resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyGamma05PminF5.shield
  5. 6
      resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyGamma09PminF3.shield
  6. 9
      resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyLambda05PminF5.shield
  7. 9
      resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyLambda09PminF3.shield
  8. 3
      resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyGamma05PminF5.shield
  9. 6
      resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyGamma09PminF3.shield
  10. 9
      resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyLambda05PminF5.shield
  11. 9
      resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyLambda09PminF3.shield
  12. 2
      src/storm-cli-utilities/model-handling.h
  13. 20
      src/storm-parsers/parser/FormulaParserGrammar.cpp
  14. 2
      src/storm-parsers/parser/FormulaParserGrammar.h
  15. 28
      src/storm/logic/ShieldExpression.cpp
  16. 9
      src/storm/logic/ShieldExpression.h
  17. 50
      src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp
  18. 45
      src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h
  19. 45
      src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h
  20. 21
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp
  21. 5
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h
  22. 96
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp
  23. 43
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h
  24. 64
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp
  25. 6
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h
  26. 9
      src/storm/modelchecker/helper/utility/SetInformationFromCheckTask.h
  27. 5
      src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
  28. 2
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  29. 14
      src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp
  30. 2
      src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp
  31. 12
      src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp
  32. 11
      src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h
  33. 8
      src/storm/shields/AbstractShield.h
  34. 54
      src/storm/shields/OptimalShield.cpp
  35. 10
      src/storm/shields/OptimalShield.h
  36. 39
      src/storm/shields/PostShield.cpp
  37. 4
      src/storm/shields/PostShield.h
  38. 38
      src/storm/shields/PreShield.cpp
  39. 4
      src/storm/shields/PreShield.h
  40. 19
      src/storm/shields/ShieldHandling.cpp
  41. 6
      src/storm/shields/ShieldHandling.h
  42. 29
      src/storm/solver/Multiplier.cpp
  43. 2
      src/storm/solver/Multiplier.h
  44. 74
      src/storm/storage/PostScheduler.cpp
  45. 22
      src/storm/storage/PostScheduler.h
  46. 63
      src/storm/storage/PostSchedulerChoice.cpp
  47. 46
      src/storm/storage/PostSchedulerChoice.h
  48. 43
      src/storm/storage/PreScheduler.cpp
  49. 28
      src/storm/storage/PreScheduler.h
  50. 56
      src/storm/storage/PreSchedulerChoice.cpp
  51. 42
      src/storm/storage/PreSchedulerChoice.h
  52. 16
      src/test/storm/modelchecker/rpatl/smg/ShieldGenerationSmgRpatlModelCheckerTest.cpp
  53. 5
      src/test/storm/parser/GameShieldingParserTest.cpp
  54. 5
      src/test/storm/parser/MdpShieldingParserTest.cpp

8
resources/examples/testfiles/shields/mdp-shields/dieSelectionPostSafetylambda07Pmin.shield

@ -1,8 +1,8 @@
___________________________________________________________________ ___________________________________________________________________
Post-Safety-Shield with relative comparison (lambda = 0.700000): Post-Safety-Shield with relative comparison (lambda = 0.700000):
model state: correction [<action>: (<corrected action>)}: model state: correction [<action>: (<corrected action>)}:
0 0: 2; 1: 2; 2: 2
1 0: 0; 1: 0; 2: 0
3 0: 2; 1: 2; 2: 2
4 0: 2; 1: 2; 2: 2
0 0: 0; 1: 1; 2: 2
1 0: 0; 1: 1; 2: 2
3 0: 0; 1: 1; 2: 2
4 0: 0; 1: 1; 2: 2
___________________________________________________________________ ___________________________________________________________________

2
resources/examples/testfiles/shields/mdp-shields/dieSelectionPreSafetygamma08Pmin.shield

@ -2,5 +2,7 @@ ___________________________________________________________________
Pre-Safety-Shield with absolute comparison (gamma = 0.800000): Pre-Safety-Shield with absolute comparison (gamma = 0.800000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
0 0.58: (0); 0.566: (1); 0.552: (2) 0 0.58: (0); 0.566: (1); 0.552: (2)
1 0.7942: (1); 0.7599: (2)
3 0.755: (0); 0.706: (1); 0.657: (2) 3 0.755: (0); 0.706: (1); 0.657: (2)
6 0.79: (1); 0.755: (2)
___________________________________________________________________ ___________________________________________________________________

7
resources/examples/testfiles/shields/mdp-shields/dieSelectionPreSafetylambda08Pmin.shield

@ -1,4 +1,11 @@
___________________________________________________________________ ___________________________________________________________________
Pre-Safety-Shield with relative comparison (lambda = 0.800000): Pre-Safety-Shield with relative comparison (lambda = 0.800000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
0 0.58: (0); 0.566: (1); 0.552: (2)
1 0.8285: (0); 0.7942: (1); 0.7599: (2)
2 0.8775: (0); 0.902: (1); 0.9265: (2)
3 0.755: (0); 0.706: (1); 0.657: (2)
4 1: (0); 1: (1); 1: (2)
5 1: (0); 1: (1); 1: (2)
6 0.825: (0); 0.79: (1); 0.755: (2)
___________________________________________________________________ ___________________________________________________________________

3
resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyGamma05PminF5.shield

@ -1,6 +1,5 @@
___________________________________________________________________ ___________________________________________________________________
Post-Safety-Shield with absolute comparison (gamma = 0.500000): Post-Safety-Shield with absolute comparison (gamma = 0.500000):
model state: correction [<action>: (<corrected action>)}: model state: correction [<action>: (<corrected action>)}:
4 0: 0
5 0: 0
7 0: 0
___________________________________________________________________ ___________________________________________________________________

6
resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyGamma09PminF3.shield

@ -1,6 +1,8 @@
___________________________________________________________________ ___________________________________________________________________
Post-Safety-Shield with absolute comparison (gamma = 0.900000): Post-Safety-Shield with absolute comparison (gamma = 0.900000):
model state: correction [<action>: (<corrected action>)}: model state: correction [<action>: (<corrected action>)}:
4 0: 0
5 0: 0
1 0: 0; 1: 0
2 0: 0
7 0: 0
10 0: 0
___________________________________________________________________ ___________________________________________________________________

9
resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyLambda05PminF5.shield

@ -1,8 +1,9 @@
___________________________________________________________________ ___________________________________________________________________
Post-Safety-Shield with relative comparison (lambda = 0.500000): Post-Safety-Shield with relative comparison (lambda = 0.500000):
model state: correction [<action>: (<corrected action>)}: model state: correction [<action>: (<corrected action>)}:
0 0: 0; 1: 1
4 0: 0
5 0: 0
9 0: 0; 1: 1
1 0: 0; 1: 1
2 0: 0
7 0: 0
8 0: 0
10 0: 0
___________________________________________________________________ ___________________________________________________________________

9
resources/examples/testfiles/shields/smg-shields/rightDecisionPostSafetyLambda09PminF3.shield

@ -1,8 +1,9 @@
___________________________________________________________________ ___________________________________________________________________
Post-Safety-Shield with relative comparison (lambda = 0.900000): Post-Safety-Shield with relative comparison (lambda = 0.900000):
model state: correction [<action>: (<corrected action>)}: model state: correction [<action>: (<corrected action>)}:
0 0: 0; 1: 1
4 0: 0
5 0: 0
9 0: 0; 1: 1
1 0: 0; 1: 1
2 0: 0
7 0: 0
8 0: 0
10 0: 0
___________________________________________________________________ ___________________________________________________________________

3
resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyGamma05PminF5.shield

@ -1,6 +1,5 @@
___________________________________________________________________ ___________________________________________________________________
Pre-Safety-Shield with absolute comparison (gamma = 0.500000): Pre-Safety-Shield with absolute comparison (gamma = 0.500000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
4 0: (0)
5 0: (0)
7 0: (0)
___________________________________________________________________ ___________________________________________________________________

6
resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyGamma09PminF3.shield

@ -1,6 +1,8 @@
___________________________________________________________________ ___________________________________________________________________
Pre-Safety-Shield with absolute comparison (gamma = 0.900000): Pre-Safety-Shield with absolute comparison (gamma = 0.900000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
4 0: (0)
5 0: (0)
1 0.9: (0)
2 0: (0)
7 0: (0)
10 0.9: (0)
___________________________________________________________________ ___________________________________________________________________

9
resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyLambda05PminF5.shield

@ -1,8 +1,9 @@
___________________________________________________________________ ___________________________________________________________________
Pre-Safety-Shield with relative comparison (lambda = 0.500000): Pre-Safety-Shield with relative comparison (lambda = 0.500000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
0 0: (1)
4 0: (0)
5 0: (0)
9 0: (1)
1 0.9: (0); 1: (1)
2 1: (0)
7 0: (0)
8 1: (0)
10 0.9: (0)
___________________________________________________________________ ___________________________________________________________________

9
resources/examples/testfiles/shields/smg-shields/rightDecisionPreSafetyLambda09PminF3.shield

@ -1,8 +1,9 @@
___________________________________________________________________ ___________________________________________________________________
Pre-Safety-Shield with relative comparison (lambda = 0.900000): Pre-Safety-Shield with relative comparison (lambda = 0.900000):
model state: choice(s) [<value>: (<action>)}: model state: choice(s) [<value>: (<action>)}:
0 0: (1)
4 0: (0)
5 0: (0)
9 0: (1)
1 0.9: (0); 1: (1)
2 0: (0)
7 0: (0)
8 1: (0)
10 0.9: (0)
___________________________________________________________________ ___________________________________________________________________

2
src/storm-cli-utilities/model-handling.h

@ -838,7 +838,7 @@ namespace storm {
void printModelCheckingProperty(storm::jani::Property const& property) { void printModelCheckingProperty(storm::jani::Property const& property) {
if(property.isShieldingProperty()) { if(property.isShieldingProperty()) {
STORM_PRINT(std::endl << "Creating a " << property.getShieldingExpression()->typeToString() << " shield for:");
STORM_PRINT(std::endl << "Creating " << property.getShieldingExpression()->typeToString() << " shield for:");
} }
STORM_PRINT(std::endl << "Model checking property \"" << property.getName() << "\": " << *property.getRawFormula() << " ..." << std::endl); STORM_PRINT(std::endl << "Model checking property \"" << property.getName() << "\": " << *property.getRawFormula() << " ..." << std::endl);
} }

20
src/storm-parsers/parser/FormulaParserGrammar.cpp

@ -184,16 +184,21 @@ namespace storm {
shieldExpression.name("shield expression"); shieldExpression.name("shield expression");
shieldingType = (qi::lit("PreSafety")[qi::_val = storm::logic::ShieldingType::PreSafety] |
qi::lit("PostSafety")[qi::_val = storm::logic::ShieldingType::PostSafety] |
qi::lit("Optimal")[qi::_val = storm::logic::ShieldingType::Optimal]) > -qi::lit("Shield");
shieldingType = (qi::lit("PreSafety")[qi::_val = storm::logic::ShieldingType::PreSafety] |
qi::lit("PostSafety")[qi::_val = storm::logic::ShieldingType::PostSafety] |
qi::lit("OptimalPre")[qi::_val = storm::logic::ShieldingType::OptimalPre] |
qi::lit("OptimalPost")[qi::_val = storm::logic::ShieldingType::OptimalPost] |
qi::lit("Optimal")[qi::_val = storm::logic::ShieldingType::OptimalPost]) // backwards compatability, will be disabled in the future
> -qi::lit("Shield");
shieldingType.name("shielding type"); shieldingType.name("shielding type");
probability = qi::double_[qi::_pass = (qi::_1 >= 0) & (qi::_1 <= 1.0), qi::_val = qi::_1 ];
probability.name("double between 0 and 1");
//probability = qi::double_[qi::_pass = (qi::_1 >= 0) & (qi::_1 <= 1.0), qi::_val = qi::_1 ];
//probability.name("double between 0 and 1");
comparisonValue = qi::double_[qi::_val = qi::_1 ];
comparisonValue.name("double comparison value");
shieldComparison = ((qi::lit("lambda")[qi::_a = storm::logic::ShieldComparison::Relative] | shieldComparison = ((qi::lit("lambda")[qi::_a = storm::logic::ShieldComparison::Relative] |
qi::lit("gamma")[qi::_a = storm::logic::ShieldComparison::Absolute]) > qi::lit("=") > probability)[qi::_val = phoenix::bind(&FormulaParserGrammar::createShieldComparisonStruct, phoenix::ref(*this), qi::_a, qi::_1)];
qi::lit("gamma")[qi::_a = storm::logic::ShieldComparison::Absolute]) > qi::lit("=") > comparisonValue)[qi::_val = phoenix::bind(&FormulaParserGrammar::createShieldComparisonStruct, phoenix::ref(*this), qi::_a, qi::_1)];
shieldComparison.name("shield comparison type"); shieldComparison.name("shield comparison type");
#pragma clang diagnostic push #pragma clang diagnostic push
@ -649,10 +654,9 @@ namespace storm {
std::shared_ptr<storm::logic::ShieldExpression const> FormulaParserGrammar::createShieldExpression(storm::logic::ShieldingType type, std::string name, boost::optional<std::pair<storm::logic::ShieldComparison, double>> comparisonStruct) { std::shared_ptr<storm::logic::ShieldExpression const> FormulaParserGrammar::createShieldExpression(storm::logic::ShieldingType type, std::string name, boost::optional<std::pair<storm::logic::ShieldComparison, double>> comparisonStruct) {
if(comparisonStruct.is_initialized()) { if(comparisonStruct.is_initialized()) {
STORM_LOG_WARN_COND(type != storm::logic::ShieldingType::Optimal , "Comparison for optimal shield will be ignored.");
return std::shared_ptr<storm::logic::ShieldExpression>(new storm::logic::ShieldExpression(type, name, comparisonStruct.get().first, comparisonStruct.get().second)); return std::shared_ptr<storm::logic::ShieldExpression>(new storm::logic::ShieldExpression(type, name, comparisonStruct.get().first, comparisonStruct.get().second));
} else { } else {
STORM_LOG_THROW(type == storm::logic::ShieldingType::Optimal , storm::exceptions::WrongFormatException, "Construction of safety shield needs a comparison parameter (lambda or gamma)");
STORM_LOG_INFO("Construction of shield without a comparison parameter (lambda or gamma) will default to 'lambda=0'");
return std::shared_ptr<storm::logic::ShieldExpression>(new storm::logic::ShieldExpression(type, name)); return std::shared_ptr<storm::logic::ShieldExpression>(new storm::logic::ShieldExpression(type, name));
} }
} }

2
src/storm-parsers/parser/FormulaParserGrammar.h

@ -237,7 +237,7 @@ namespace storm {
// Shielding properties // Shielding properties
qi::rule<Iterator, std::shared_ptr<storm::logic::ShieldExpression const>(), Skipper> shieldExpression; qi::rule<Iterator, std::shared_ptr<storm::logic::ShieldExpression const>(), Skipper> shieldExpression;
qi::rule<Iterator, storm::logic::ShieldingType, Skipper> shieldingType; qi::rule<Iterator, storm::logic::ShieldingType, Skipper> shieldingType;
qi::rule<Iterator, double, Skipper> probability;
qi::rule<Iterator, double, Skipper> comparisonValue;
qi::rule<Iterator, std::pair<storm::logic::ShieldComparison, double>, qi::locals<storm::logic::ShieldComparison>, Skipper> shieldComparison; qi::rule<Iterator, std::pair<storm::logic::ShieldComparison, double>, qi::locals<storm::logic::ShieldComparison>, Skipper> shieldComparison;
// Start symbol // Start symbol

28
src/storm/logic/ShieldExpression.cpp

@ -27,7 +27,15 @@ namespace storm {
} }
bool ShieldExpression::isOptimalShield() const { bool ShieldExpression::isOptimalShield() const {
return type == storm::logic::ShieldingType::Optimal;
return type == storm::logic::ShieldingType::OptimalPre || type == storm::logic::ShieldingType::OptimalPost;
}
bool ShieldExpression::isOptimalPreShield() const {
return type == storm::logic::ShieldingType::OptimalPre;
}
bool ShieldExpression::isOptimalPostShield() const {
return type == storm::logic::ShieldingType::OptimalPost;
} }
double ShieldExpression::getValue() const { double ShieldExpression::getValue() const {
@ -36,9 +44,10 @@ namespace storm {
std::string ShieldExpression::typeToString() const { std::string ShieldExpression::typeToString() const {
switch(type) { switch(type) {
case storm::logic::ShieldingType::PostSafety: return "PostSafety";
case storm::logic::ShieldingType::PreSafety: return "PreSafety";
case storm::logic::ShieldingType::Optimal: return "Optimal";
case storm::logic::ShieldingType::PostSafety: return "Post";
case storm::logic::ShieldingType::PreSafety: return "Pre";
case storm::logic::ShieldingType::OptimalPre: return "OptimalPre";
case storm::logic::ShieldingType::OptimalPost: return "OptimalPost";
} }
} }
@ -57,14 +66,13 @@ namespace storm {
std::string prettyString = ""; std::string prettyString = "";
std::string comparisonType = isRelative() ? "relative" : "absolute"; std::string comparisonType = isRelative() ? "relative" : "absolute";
switch(type) { switch(type) {
case storm::logic::ShieldingType::PostSafety: prettyString += "Post-Safety"; break;
case storm::logic::ShieldingType::PreSafety: prettyString += "Pre-Safety"; break;
case storm::logic::ShieldingType::Optimal: prettyString += "Optimal"; break;
case storm::logic::ShieldingType::PostSafety: prettyString += "Post-Safety"; break;
case storm::logic::ShieldingType::PreSafety: prettyString += "Pre-Safety"; break;
case storm::logic::ShieldingType::OptimalPre: prettyString += "Optimal-Pre"; break;
case storm::logic::ShieldingType::OptimalPost: prettyString += "Optimal-Post"; break;
} }
prettyString += "-Shield "; prettyString += "-Shield ";
if(!(type == storm::logic::ShieldingType::Optimal)) {
prettyString += "with " + comparisonType + " comparison (" + comparisonToString() + " = " + std::to_string(value) + "):";
}
prettyString += "with " + comparisonType + " comparison (" + comparisonToString() + " = " + std::to_string(value) + "):";
return prettyString; return prettyString;
} }

9
src/storm/logic/ShieldExpression.h

@ -9,7 +9,8 @@ namespace storm {
enum class ShieldingType { enum class ShieldingType {
PostSafety, PostSafety,
PreSafety, PreSafety,
Optimal
OptimalPre,
OptimalPost
}; };
enum class ShieldComparison { Absolute, Relative }; enum class ShieldComparison { Absolute, Relative };
@ -24,6 +25,8 @@ namespace storm {
bool isPreSafetyShield() const; bool isPreSafetyShield() const;
bool isPostSafetyShield() const; bool isPostSafetyShield() const;
bool isOptimalShield() const; bool isOptimalShield() const;
bool isOptimalPreShield() const;
bool isOptimalPostShield() const;
double getValue() const; double getValue() const;
@ -36,8 +39,8 @@ namespace storm {
private: private:
ShieldingType type; ShieldingType type;
ShieldComparison comparison;
double value;
ShieldComparison comparison = ShieldComparison::Relative;
double value = 0;
std::string filename; std::string filename;
}; };

50
src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp

@ -4,85 +4,95 @@
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::SingleValueModelCheckerHelper() : _produceScheduler(false) { SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::SingleValueModelCheckerHelper() : _produceScheduler(false) {
// Intentionally left empty // Intentionally left empty
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setOptimizationDirection(storm::solver::OptimizationDirection const& direction) { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setOptimizationDirection(storm::solver::OptimizationDirection const& direction) {
_optimizationDirection = direction; _optimizationDirection = direction;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::clearOptimizationDirection() { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::clearOptimizationDirection() {
_optimizationDirection = boost::none; _optimizationDirection = boost::none;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isOptimizationDirectionSet() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isOptimizationDirectionSet() const {
return _optimizationDirection.is_initialized(); return _optimizationDirection.is_initialized();
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
storm::solver::OptimizationDirection const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getOptimizationDirection() const { storm::solver::OptimizationDirection const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getOptimizationDirection() const {
STORM_LOG_ASSERT(isOptimizationDirectionSet(), "Requested optimization direction but none was set."); STORM_LOG_ASSERT(isOptimizationDirectionSet(), "Requested optimization direction but none was set.");
return _optimizationDirection.get(); return _optimizationDirection.get();
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::minimize() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::minimize() const {
return storm::solver::minimize(getOptimizationDirection()); return storm::solver::minimize(getOptimizationDirection());
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::maximize() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::maximize() const {
return storm::solver::maximize(getOptimizationDirection()); return storm::solver::maximize(getOptimizationDirection());
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
boost::optional<storm::solver::OptimizationDirection> SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getOptionalOptimizationDirection() const { boost::optional<storm::solver::OptimizationDirection> SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getOptionalOptimizationDirection() const {
return _optimizationDirection; return _optimizationDirection;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setValueThreshold(storm::logic::ComparisonType const& comparisonType, ValueType const& threshold) { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setValueThreshold(storm::logic::ComparisonType const& comparisonType, ValueType const& threshold) {
_valueThreshold = std::make_pair(comparisonType, threshold); _valueThreshold = std::make_pair(comparisonType, threshold);
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::clearValueThreshold() { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::clearValueThreshold() {
_valueThreshold = boost::none; _valueThreshold = boost::none;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isValueThresholdSet() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isValueThresholdSet() const {
return _valueThreshold.is_initialized(); return _valueThreshold.is_initialized();
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
storm::logic::ComparisonType const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getValueThresholdComparisonType() const { storm::logic::ComparisonType const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getValueThresholdComparisonType() const {
STORM_LOG_ASSERT(isValueThresholdSet(), "Value Threshold comparison type was requested but not set before."); STORM_LOG_ASSERT(isValueThresholdSet(), "Value Threshold comparison type was requested but not set before.");
return _valueThreshold->first; return _valueThreshold->first;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
ValueType const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getValueThresholdValue() const { ValueType const& SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::getValueThresholdValue() const {
STORM_LOG_ASSERT(isValueThresholdSet(), "Value Threshold comparison type was requested but not set before."); STORM_LOG_ASSERT(isValueThresholdSet(), "Value Threshold comparison type was requested but not set before.");
return _valueThreshold->second; return _valueThreshold->second;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setProduceScheduler(bool value) { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setProduceScheduler(bool value) {
_produceScheduler = value; _produceScheduler = value;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isProduceSchedulerSet() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isProduceSchedulerSet() const {
return _produceScheduler; return _produceScheduler;
} }
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setProduceChoiceValues(bool value) {
_produceChoiceValues = value;
}
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isProduceChoiceValuesSet() const {
return _produceChoiceValues;
}
template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation> template <typename ValueType, storm::models::ModelRepresentation ModelRepresentation>
void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setQualitative(bool value) { void SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::setQualitative(bool value) {
_isQualitativeSet = value; _isQualitativeSet = value;
@ -92,17 +102,17 @@ namespace storm {
bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isQualitativeSet() const { bool SingleValueModelCheckerHelper<ValueType, ModelRepresentation>::isQualitativeSet() const {
return _isQualitativeSet; return _isQualitativeSet;
} }
template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::Sparse>; template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::Sparse>;
template class SingleValueModelCheckerHelper<storm::RationalNumber, storm::models::ModelRepresentation::Sparse>; template class SingleValueModelCheckerHelper<storm::RationalNumber, storm::models::ModelRepresentation::Sparse>;
template class SingleValueModelCheckerHelper<storm::RationalFunction, storm::models::ModelRepresentation::Sparse>; template class SingleValueModelCheckerHelper<storm::RationalFunction, storm::models::ModelRepresentation::Sparse>;
template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::DdSylvan>; template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::DdSylvan>;
template class SingleValueModelCheckerHelper<storm::RationalNumber, storm::models::ModelRepresentation::DdSylvan>; template class SingleValueModelCheckerHelper<storm::RationalNumber, storm::models::ModelRepresentation::DdSylvan>;
template class SingleValueModelCheckerHelper<storm::RationalFunction, storm::models::ModelRepresentation::DdSylvan>; template class SingleValueModelCheckerHelper<storm::RationalFunction, storm::models::ModelRepresentation::DdSylvan>;
template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::DdCudd>; template class SingleValueModelCheckerHelper<double, storm::models::ModelRepresentation::DdCudd>;
} }
} }
}
}

45
src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h

@ -8,7 +8,7 @@
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
/*! /*!
* Helper for model checking queries where we are interested in (optimizing) a single value per state. * Helper for model checking queries where we are interested in (optimizing) a single value per state.
* @tparam ValueType The type of a value * @tparam ValueType The type of a value
@ -19,47 +19,47 @@ namespace storm {
public: public:
SingleValueModelCheckerHelper(); SingleValueModelCheckerHelper();
/*! /*!
* Sets the optimization direction, i.e., whether we want to minimize or maximize the value for each state * Sets the optimization direction, i.e., whether we want to minimize or maximize the value for each state
* Has no effect for models without nondeterminism. * Has no effect for models without nondeterminism.
* Has to be set if there is nondeterminism in the model. * Has to be set if there is nondeterminism in the model.
*/ */
void setOptimizationDirection(storm::solver::OptimizationDirection const& direction); void setOptimizationDirection(storm::solver::OptimizationDirection const& direction);
/*! /*!
* Clears the optimization direction if it was set before. * Clears the optimization direction if it was set before.
*/ */
void clearOptimizationDirection(); void clearOptimizationDirection();
/*! /*!
* @return true if there is an optimization direction set * @return true if there is an optimization direction set
*/ */
bool isOptimizationDirectionSet() const; bool isOptimizationDirectionSet() const;
/*! /*!
* @pre an optimization direction has to be set before calling this. * @pre an optimization direction has to be set before calling this.
* @return the optimization direction. * @return the optimization direction.
*/ */
storm::solver::OptimizationDirection const& getOptimizationDirection() const; storm::solver::OptimizationDirection const& getOptimizationDirection() const;
/*! /*!
* @pre an optimization direction has to be set before calling this. * @pre an optimization direction has to be set before calling this.
* @return true iff the optimization goal is to minimize the value for each state * @return true iff the optimization goal is to minimize the value for each state
*/ */
bool minimize() const; bool minimize() const;
/*! /*!
* @pre an optimization direction has to be set before calling this. * @pre an optimization direction has to be set before calling this.
* @return true iff the optimization goal is to maximize the value for each state * @return true iff the optimization goal is to maximize the value for each state
*/ */
bool maximize() const; bool maximize() const;
/*! /*!
* @return The optimization direction (if it was set) * @return The optimization direction (if it was set)
*/ */
boost::optional<storm::solver::OptimizationDirection> getOptionalOptimizationDirection() const; boost::optional<storm::solver::OptimizationDirection> getOptionalOptimizationDirection() const;
/*! /*!
* Sets a goal threshold for the value at each state. If such a threshold is set, it is assumed that we are only interested * Sets a goal threshold for the value at each state. If such a threshold is set, it is assumed that we are only interested
* in the satisfaction of the threshold. Setting this allows the helper to compute values only up to the precision * in the satisfaction of the threshold. Setting this allows the helper to compute values only up to the precision
@ -68,39 +68,49 @@ namespace storm {
* @param thresholdValue The value used on the right hand side of the comparison relation. * @param thresholdValue The value used on the right hand side of the comparison relation.
*/ */
void setValueThreshold(storm::logic::ComparisonType const& comparisonType, ValueType const& thresholdValue); void setValueThreshold(storm::logic::ComparisonType const& comparisonType, ValueType const& thresholdValue);
/*! /*!
* Clears the valueThreshold if it was set before. * Clears the valueThreshold if it was set before.
*/ */
void clearValueThreshold(); void clearValueThreshold();
/*! /*!
* @return true, if a value threshold has been set. * @return true, if a value threshold has been set.
*/ */
bool isValueThresholdSet() const; bool isValueThresholdSet() const;
/*! /*!
* @pre A value threshold has to be set before calling this. * @pre A value threshold has to be set before calling this.
* @return The relation used when comparing computed values (left hand side) with the specified threshold value (right hand side). * @return The relation used when comparing computed values (left hand side) with the specified threshold value (right hand side).
*/ */
storm::logic::ComparisonType const& getValueThresholdComparisonType() const; storm::logic::ComparisonType const& getValueThresholdComparisonType() const;
/*! /*!
* @pre A value threshold has to be set before calling this. * @pre A value threshold has to be set before calling this.
* @return The value used on the right hand side of the comparison relation. * @return The value used on the right hand side of the comparison relation.
*/ */
ValueType const& getValueThresholdValue() const; ValueType const& getValueThresholdValue() const;
/*! /*!
* Sets whether an optimal scheduler shall be constructed during the computation * Sets whether an optimal scheduler shall be constructed during the computation
*/ */
void setProduceScheduler(bool value); void setProduceScheduler(bool value);
/*! /*!
* @return whether an optimal scheduler shall be constructed during the computation * @return whether an optimal scheduler shall be constructed during the computation
*/ */
bool isProduceSchedulerSet() const; bool isProduceSchedulerSet() const;
/*!
* Sets whether all choice values shall be computed
*/
void setProduceChoiceValues(bool value);
/*!
* @return whether all choice values shall be computed
*/
bool isProduceChoiceValuesSet() const;
/*! /*!
* Sets whether the property needs to be checked qualitatively * Sets whether the property needs to be checked qualitatively
*/ */
@ -110,13 +120,14 @@ namespace storm {
* @return whether the property needs to be checked qualitatively * @return whether the property needs to be checked qualitatively
*/ */
bool isQualitativeSet() const; bool isQualitativeSet() const;
private: private:
boost::optional<storm::solver::OptimizationDirection> _optimizationDirection; boost::optional<storm::solver::OptimizationDirection> _optimizationDirection;
boost::optional<std::pair<storm::logic::ComparisonType, ValueType>> _valueThreshold; boost::optional<std::pair<storm::logic::ComparisonType, ValueType>> _valueThreshold;
bool _produceScheduler; bool _produceScheduler;
bool _produceChoiceValues;
bool _isQualitativeSet; bool _isQualitativeSet;
}; };
} }
} }
}
}

45
src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h

@ -8,16 +8,16 @@
namespace storm { namespace storm {
class Environment; class Environment;
namespace models { namespace models {
namespace sparse { namespace sparse {
template <typename VT> class StandardRewardModel; template <typename VT> class StandardRewardModel;
} }
} }
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
/*! /*!
* Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system. * Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system.
* @tparam ValueType the type a value can have * @tparam ValueType the type a value can have
@ -27,22 +27,22 @@ namespace storm {
class SparseInfiniteHorizonHelper : public SingleValueModelCheckerHelper<ValueType, storm::models::ModelRepresentation::Sparse> { class SparseInfiniteHorizonHelper : public SingleValueModelCheckerHelper<ValueType, storm::models::ModelRepresentation::Sparse> {
public: public:
/*! /*!
* The type of a component in which the system resides in the long run (BSCC for deterministic models, MEC for nondeterministic models) * The type of a component in which the system resides in the long run (BSCC for deterministic models, MEC for nondeterministic models)
*/ */
using LongRunComponentType = typename std::conditional<Nondeterministic, storm::storage::MaximalEndComponent, storm::storage::StronglyConnectedComponent>::type; using LongRunComponentType = typename std::conditional<Nondeterministic, storm::storage::MaximalEndComponent, storm::storage::StronglyConnectedComponent>::type;
/*! /*!
* Function mapping from indices to values * Function mapping from indices to values
*/ */
typedef std::function<ValueType(uint64_t)> ValueGetter; typedef std::function<ValueType(uint64_t)> ValueGetter;
/*! /*!
* Initializes the helper for a discrete time (i.e. DTMC, MDP) * Initializes the helper for a discrete time (i.e. DTMC, MDP)
*/ */
SparseInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix); SparseInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix);
/*! /*!
* Initializes the helper for continuous time (i.e. MA) * Initializes the helper for continuous time (i.e. MA)
*/ */
@ -52,33 +52,33 @@ namespace storm {
* Initializes the helper for continuous time (i.e. CTMC) * Initializes the helper for continuous time (i.e. CTMC)
*/ */
SparseInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates); SparseInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates);
/*! /*!
* Provides backward transitions that can be used during the computation. * Provides backward transitions that can be used during the computation.
* Providing them is optional. If they are not provided, they will be computed internally * Providing them is optional. If they are not provided, they will be computed internally
* Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the backwardstransitions remains valid. * Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the backwardstransitions remains valid.
*/ */
void provideBackwardTransitions(storm::storage::SparseMatrix<ValueType> const& backwardsTransitions); void provideBackwardTransitions(storm::storage::SparseMatrix<ValueType> const& backwardsTransitions);
/*! /*!
* Provides the decomposition into long run components (BSCCs/MECs) that can be used during the computation. * Provides the decomposition into long run components (BSCCs/MECs) that can be used during the computation.
* Providing the decomposition is optional. If it is not provided, they will be computed internally. * Providing the decomposition is optional. If it is not provided, they will be computed internally.
* Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the decomposition remains valid. * Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the decomposition remains valid.
*/ */
void provideLongRunComponentDecomposition(storm::storage::Decomposition<LongRunComponentType> const& decomposition); void provideLongRunComponentDecomposition(storm::storage::Decomposition<LongRunComponentType> const& decomposition);
/*! /*!
* Computes the long run average probabilities, i.e., the fraction of the time we are in a psiState * Computes the long run average probabilities, i.e., the fraction of the time we are in a psiState
* @return a value for each state * @return a value for each state
*/ */
std::vector<ValueType> computeLongRunAverageProbabilities(Environment const& env, storm::storage::BitVector const& psiStates); std::vector<ValueType> computeLongRunAverageProbabilities(Environment const& env, storm::storage::BitVector const& psiStates);
/*! /*!
* Computes the long run average rewards, i.e., the average reward collected per time unit * Computes the long run average rewards, i.e., the average reward collected per time unit
* @return a value for each state * @return a value for each state
*/ */
std::vector<ValueType> computeLongRunAverageRewards(Environment const& env, storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel); std::vector<ValueType> computeLongRunAverageRewards(Environment const& env, storm::models::sparse::StandardRewardModel<ValueType> const& rewardModel);
/*! /*!
* Computes the long run average value given the provided state and action-based rewards. * Computes the long run average value given the provided state and action-based rewards.
* @param stateValues a vector containing a value for every state * @param stateValues a vector containing a value for every state
@ -86,7 +86,7 @@ namespace storm {
* @return a value for each state * @return a value for each state
*/ */
std::vector<ValueType> computeLongRunAverageValues(Environment const& env, std::vector<ValueType> const* stateValues = nullptr, std::vector<ValueType> const* actionValues = nullptr); std::vector<ValueType> computeLongRunAverageValues(Environment const& env, std::vector<ValueType> const* stateValues = nullptr, std::vector<ValueType> const* actionValues = nullptr);
/*! /*!
* Computes the long run average value given the provided state and action based rewards * Computes the long run average value given the provided state and action based rewards
* @param stateValuesGetter a function returning a value for a given state index * @param stateValuesGetter a function returning a value for a given state index
@ -102,39 +102,40 @@ namespace storm {
* @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for the states of the given component which yield the returned LRA value. Choices for states outside of the component are not affected. * @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for the states of the given component which yield the returned LRA value. Choices for states outside of the component are not affected.
*/ */
virtual ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, LongRunComponentType const& component) = 0; virtual ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, LongRunComponentType const& component) = 0;
protected: protected:
/*! /*!
* @return true iff this is a computation on a continuous time model (i.e. CTMC, MA) * @return true iff this is a computation on a continuous time model (i.e. CTMC, MA)
*/ */
bool isContinuousTime() const; bool isContinuousTime() const;
/*! /*!
* @post _longRunComponentDecomposition points to a decomposition of the long run components (MECs, BSCCs) * @post _longRunComponentDecomposition points to a decomposition of the long run components (MECs, BSCCs)
*/ */
virtual void createDecomposition() = 0; virtual void createDecomposition() = 0;
/*! /*!
* @pre if scheduler production is enabled and Nondeterministic is true, a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components. * @pre if scheduler production is enabled and Nondeterministic is true, a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components.
* @return Lra values for each state * @return Lra values for each state
* @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values. * @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values.
*/ */
virtual std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues) = 0; virtual std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues) = 0;
storm::storage::SparseMatrix<ValueType> const& _transitionMatrix; storm::storage::SparseMatrix<ValueType> const& _transitionMatrix;
storm::storage::BitVector const* _markovianStates; storm::storage::BitVector const* _markovianStates;
std::vector<ValueType> const* _exitRates; std::vector<ValueType> const* _exitRates;
storm::storage::SparseMatrix<ValueType> const* _backwardTransitions; storm::storage::SparseMatrix<ValueType> const* _backwardTransitions;
storm::storage::Decomposition<LongRunComponentType> const* _longRunComponentDecomposition; storm::storage::Decomposition<LongRunComponentType> const* _longRunComponentDecomposition;
std::unique_ptr<storm::storage::SparseMatrix<ValueType>> _computedBackwardTransitions; std::unique_ptr<storm::storage::SparseMatrix<ValueType>> _computedBackwardTransitions;
std::unique_ptr<storm::storage::Decomposition<LongRunComponentType>> _computedLongRunComponentDecomposition; std::unique_ptr<storm::storage::Decomposition<LongRunComponentType>> _computedLongRunComponentDecomposition;
boost::optional<std::vector<uint64_t>> _producedOptimalChoices; boost::optional<std::vector<uint64_t>> _producedOptimalChoices;
boost::optional<std::vector<ValueType>> _choiceValues;
}; };
} }
} }
}
}

21
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp

@ -52,6 +52,12 @@ namespace storm {
return scheduler; return scheduler;
} }
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::getChoiceValues() const {
STORM_LOG_ASSERT(this->isProduceChoiceValuesSet(), "Trying to get the computed choice values although this was not requested.");
STORM_LOG_ASSERT(this->_choiceValues.is_initialized(), "Trying to get the computed choice values but none were available. Was there a computation call before?");
return this->_choiceValues.get();
}
template <typename ValueType> template <typename ValueType>
void SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::createDecomposition() { void SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::createDecomposition() {
@ -65,8 +71,6 @@ namespace storm {
this->_computedLongRunComponentDecomposition = std::make_unique<storm::storage::GameMaximalEndComponentDecomposition<ValueType>>(this->_transitionMatrix, *this->_backwardTransitions); this->_computedLongRunComponentDecomposition = std::make_unique<storm::storage::GameMaximalEndComponentDecomposition<ValueType>>(this->_transitionMatrix, *this->_backwardTransitions);
this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get(); this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get();
//STORM_LOG_DEBUG("\n" << this->_transitionMatrix);
STORM_LOG_DEBUG("GMEC: " << *(this->_longRunComponentDecomposition));
} }
} }
@ -91,6 +95,13 @@ namespace storm {
} }
this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount()); this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount());
} }
// Allocate memory for the choice values.
if (this->isProduceChoiceValuesSet()) {
if (!this->_choiceValues.is_initialized()) {
this->_choiceValues.emplace();
}
this->_choiceValues->resize(this->_transitionMatrix.getRowCount());
}
storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod(); storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod();
if (method == storm::solver::LraMethod::LinearProgramming) { if (method == storm::solver::LraMethod::LinearProgramming) {
@ -111,13 +122,17 @@ namespace storm {
if (this->isProduceSchedulerSet()) { if (this->isProduceSchedulerSet()) {
optimalChoices = &this->_producedOptimalChoices.get(); optimalChoices = &this->_producedOptimalChoices.get();
} }
std::vector<ValueType>* choiceValues = nullptr;
if (this->isProduceChoiceValuesSet()) {
choiceValues = &this->_choiceValues.get();
}
// Now create a helper and perform the algorithm // Now create a helper and perform the algorithm
if (this->isContinuousTime()) { if (this->isContinuousTime()) {
STORM_LOG_THROW(false, storm::exceptions::InternalException, "We cannot handle continuous time games."); STORM_LOG_THROW(false, storm::exceptions::InternalException, "We cannot handle continuous time games.");
} else { } else {
storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::GameNondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor, nullptr, nullptr, &statesOfCoalition); storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::GameNondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor, nullptr, nullptr, &statesOfCoalition);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices, choiceValues);
} }
} }

5
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h

@ -58,6 +58,11 @@ namespace storm {
*/ */
storm::storage::Scheduler<ValueType> extractScheduler() const; storm::storage::Scheduler<ValueType> extractScheduler() const;
/*!
* @return the computed choice values for the states.
*/
std::vector<ValueType> getChoiceValues() const;
ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component); ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component);
ValueType computeLraVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec); ValueType computeLraVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);

96
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp

@ -22,31 +22,31 @@
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
template <typename ValueType> template <typename ValueType>
SparseNondeterministicInfiniteHorizonHelper<ValueType>::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix) { SparseNondeterministicInfiniteHorizonHelper<ValueType>::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix) {
// Intentionally left empty. // Intentionally left empty.
} }
template <typename ValueType> template <typename ValueType>
SparseNondeterministicInfiniteHorizonHelper<ValueType>::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix, markovianStates, exitRates) { SparseNondeterministicInfiniteHorizonHelper<ValueType>::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix, markovianStates, exitRates) {
// Intentionally left empty. // Intentionally left empty.
} }
template <typename ValueType> template <typename ValueType>
std::vector<uint64_t> const& SparseNondeterministicInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() const { std::vector<uint64_t> const& SparseNondeterministicInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() const {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get(); return this->_producedOptimalChoices.get();
} }
template <typename ValueType> template <typename ValueType>
std::vector<uint64_t>& SparseNondeterministicInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() { std::vector<uint64_t>& SparseNondeterministicInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get(); return this->_producedOptimalChoices.get();
} }
template <typename ValueType> template <typename ValueType>
storm::storage::Scheduler<ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::extractScheduler() const { storm::storage::Scheduler<ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::extractScheduler() const {
auto const& optimalChoices = getProducedOptimalChoices(); auto const& optimalChoices = getProducedOptimalChoices();
@ -56,7 +56,14 @@ namespace storm {
} }
return scheduler; return scheduler;
} }
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::getChoiceValues() const {
STORM_LOG_ASSERT(this->isProduceChoiceValuesSet(), "Trying to get the computed choice values although this was not requested.");
STORM_LOG_ASSERT(this->_choiceValues.is_initialized(), "Trying to get the computed choice values but none were available. Was there a computation call before?");
return this->_choiceValues.get();
}
template <typename ValueType> template <typename ValueType>
void SparseNondeterministicInfiniteHorizonHelper<ValueType>::createDecomposition() { void SparseNondeterministicInfiniteHorizonHelper<ValueType>::createDecomposition() {
if (this->_longRunComponentDecomposition == nullptr) { if (this->_longRunComponentDecomposition == nullptr) {
@ -73,7 +80,7 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) { ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) {
// For models with potential nondeterminisim, we compute the LRA for a maximal end component (MEC) // For models with potential nondeterminisim, we compute the LRA for a maximal end component (MEC)
// Allocate memory for the nondeterministic choices. // Allocate memory for the nondeterministic choices.
if (this->isProduceSchedulerSet()) { if (this->isProduceSchedulerSet()) {
if (!this->_producedOptimalChoices.is_initialized()) { if (!this->_producedOptimalChoices.is_initialized()) {
@ -81,12 +88,19 @@ namespace storm {
} }
this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount()); this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount());
} }
// Allocate memory for the choice values.
if (this->isProduceChoiceValuesSet()) {
if (!this->_choiceValues.is_initialized()) {
this->_choiceValues.emplace();
}
this->_choiceValues->resize(this->_transitionMatrix.getRowCount());
}
auto trivialResult = this->computeLraForTrivialMec(env, stateRewardsGetter, actionRewardsGetter, component); auto trivialResult = this->computeLraForTrivialMec(env, stateRewardsGetter, actionRewardsGetter, component);
if (trivialResult.first) { if (trivialResult.first) {
return trivialResult.second; return trivialResult.second;
} }
// Solve nontrivial MEC with the method specified in the settings // Solve nontrivial MEC with the method specified in the settings
storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod(); storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod();
if ((storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()) && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) { if ((storm::NumberTraits<ValueType>::IsExact || env.solver().isForceExact()) && env.solver().lra().isNondetLraMethodSetFromDefault() && method != storm::solver::LraMethod::LinearProgramming) {
@ -105,10 +119,10 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique.");
} }
} }
template <typename ValueType> template <typename ValueType>
std::pair<bool, ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForTrivialMec(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) { std::pair<bool, ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForTrivialMec(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) {
// If the component only consists of a single state, we compute the LRA value directly // If the component only consists of a single state, we compute the LRA value directly
if (component.size() == 1) { if (component.size() == 1) {
auto const& element = *component.begin(); auto const& element = *component.begin();
@ -145,8 +159,8 @@ namespace storm {
} }
return {false, storm::utility::zero<ValueType>()}; return {false, storm::utility::zero<ValueType>()};
} }
template <typename ValueType> template <typename ValueType>
ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForMecVi(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) { ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForMecVi(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) {
@ -156,7 +170,11 @@ namespace storm {
if (this->isProduceSchedulerSet()) { if (this->isProduceSchedulerSet()) {
optimalChoices = &this->_producedOptimalChoices.get(); optimalChoices = &this->_producedOptimalChoices.get();
} }
std::vector<ValueType>* choiceValues = nullptr;
if (this->isProduceChoiceValuesSet()) {
choiceValues = &this->_choiceValues.get();
}
// Now create a helper and perform the algorithm // Now create a helper and perform the algorithm
if (this->isContinuousTime()) { if (this->isContinuousTime()) {
// We assume a Markov Automaton (with deterministic timed states and nondeterministic instant states) // We assume a Markov Automaton (with deterministic timed states and nondeterministic instant states)
@ -165,19 +183,19 @@ namespace storm {
} else { } else {
// We assume an MDP (with nondeterministic timed states and no instant states) // We assume an MDP (with nondeterministic timed states and no instant states)
storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::NondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor); storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::NondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices, choiceValues);
} }
} }
template <typename ValueType> template <typename ValueType>
ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForMecLp(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) { ValueType SparseNondeterministicInfiniteHorizonHelper<ValueType>::computeLraForMecLp(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) {
// Create an LP solver // Create an LP solver
auto solver = storm::utility::solver::LpSolverFactory<ValueType>().create("LRA for MEC"); auto solver = storm::utility::solver::LpSolverFactory<ValueType>().create("LRA for MEC");
// Now build the LP formulation as described in: // Now build the LP formulation as described in:
// Guck et al.: Modelling and Analysis of Markov Reward Automata (ATVA'14), https://doi.org/10.1007/978-3-319-11936-6_13 // Guck et al.: Modelling and Analysis of Markov Reward Automata (ATVA'14), https://doi.org/10.1007/978-3-319-11936-6_13
solver->setOptimizationDirection(invert(this->getOptimizationDirection())); solver->setOptimizationDirection(invert(this->getOptimizationDirection()));
// Create variables // Create variables
// TODO: Investigate whether we can easily make the variables bounded // TODO: Investigate whether we can easily make the variables bounded
std::map<uint_fast64_t, storm::expressions::Variable> stateToVariableMap; std::map<uint_fast64_t, storm::expressions::Variable> stateToVariableMap;
@ -187,12 +205,12 @@ namespace storm {
} }
storm::expressions::Variable k = solver->addUnboundedContinuousVariable("k", storm::utility::one<ValueType>()); storm::expressions::Variable k = solver->addUnboundedContinuousVariable("k", storm::utility::one<ValueType>());
solver->update(); solver->update();
// Add constraints. // Add constraints.
for (auto const& stateChoicesPair : mec) { for (auto const& stateChoicesPair : mec) {
uint_fast64_t state = stateChoicesPair.first; uint_fast64_t state = stateChoicesPair.first;
bool stateIsMarkovian = this->_markovianStates && this->_markovianStates->get(state); bool stateIsMarkovian = this->_markovianStates && this->_markovianStates->get(state);
// Now create a suitable constraint for each choice // Now create a suitable constraint for each choice
// x_s {≤, ≥} -k/rate(s) + sum_s' P(s,act,s') * x_s' + (value(s)/rate(s) + value(s,act)) // x_s {≤, ≥} -k/rate(s) + sum_s' P(s,act,s') * x_s' + (value(s)/rate(s) + value(s,act))
for (auto choice : stateChoicesPair.second) { for (auto choice : stateChoicesPair.second) {
@ -231,12 +249,12 @@ namespace storm {
solver->addConstraint("s" + std::to_string(state) + "," + std::to_string(choice), constraint); solver->addConstraint("s" + std::to_string(state) + "," + std::to_string(choice), constraint);
} }
} }
solver->optimize(); solver->optimize();
STORM_LOG_THROW(!this->isProduceSchedulerSet(), storm::exceptions::NotImplementedException, "Scheduler extraction is not yet implemented for LP based LRA method."); STORM_LOG_THROW(!this->isProduceSchedulerSet(), storm::exceptions::NotImplementedException, "Scheduler extraction is not yet implemented for LP based LRA method.");
return solver->getContinuousValue(k); return solver->getContinuousValue(k);
} }
/*! /*!
* Auxiliary function that adds the entries of the Ssp Matrix for a single choice (i.e., row) * Auxiliary function that adds the entries of the Ssp Matrix for a single choice (i.e., row)
* Transitions that lead to a Component state will be redirected to a new auxiliary state (there is one aux. state for each component). * Transitions that lead to a Component state will be redirected to a new auxiliary state (there is one aux. state for each component).
@ -244,10 +262,10 @@ namespace storm {
*/ */
template <typename ValueType> template <typename ValueType>
void addSspMatrixChoice(uint64_t const& inputMatrixChoice, storm::storage::SparseMatrix<ValueType> const& inputTransitionMatrix, std::vector<uint64_t> const& inputToSspStateMap, uint64_t const& numberOfNonComponentStates, uint64_t const& currentSspChoice, storm::storage::SparseMatrixBuilder<ValueType>& sspMatrixBuilder) { void addSspMatrixChoice(uint64_t const& inputMatrixChoice, storm::storage::SparseMatrix<ValueType> const& inputTransitionMatrix, std::vector<uint64_t> const& inputToSspStateMap, uint64_t const& numberOfNonComponentStates, uint64_t const& currentSspChoice, storm::storage::SparseMatrixBuilder<ValueType>& sspMatrixBuilder) {
// As there could be multiple transitions to the same MEC, we accumulate them in this map before adding them to the matrix builder. // As there could be multiple transitions to the same MEC, we accumulate them in this map before adding them to the matrix builder.
std::map<uint64_t, ValueType> auxiliaryStateToProbabilityMap; std::map<uint64_t, ValueType> auxiliaryStateToProbabilityMap;
for (auto const& transition : inputTransitionMatrix.getRow(inputMatrixChoice)) { for (auto const& transition : inputTransitionMatrix.getRow(inputMatrixChoice)) {
if (!storm::utility::isZero(transition.getValue())) { if (!storm::utility::isZero(transition.getValue())) {
auto const& sspTransitionTarget = inputToSspStateMap[transition.getColumn()]; auto const& sspTransitionTarget = inputToSspStateMap[transition.getColumn()];
@ -268,18 +286,18 @@ namespace storm {
} }
} }
} }
// Now insert all (cumulative) probability values that target a component. // Now insert all (cumulative) probability values that target a component.
for (auto const& componentToProbEntry : auxiliaryStateToProbabilityMap) { for (auto const& componentToProbEntry : auxiliaryStateToProbabilityMap) {
sspMatrixBuilder.addNextValue(currentSspChoice, componentToProbEntry.first, componentToProbEntry.second); sspMatrixBuilder.addNextValue(currentSspChoice, componentToProbEntry.first, componentToProbEntry.second);
} }
} }
template <typename ValueType> template <typename ValueType>
std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> SparseNondeterministicInfiniteHorizonHelper<ValueType>::buildSspMatrixVector(std::vector<ValueType> const& mecLraValues, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>>* sspComponentExitChoicesToOriginalMap) { std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> SparseNondeterministicInfiniteHorizonHelper<ValueType>::buildSspMatrixVector(std::vector<ValueType> const& mecLraValues, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>>* sspComponentExitChoicesToOriginalMap) {
auto const& choiceIndices = this->_transitionMatrix.getRowGroupIndices(); auto const& choiceIndices = this->_transitionMatrix.getRowGroupIndices();
std::vector<ValueType> rhs; std::vector<ValueType> rhs;
uint64_t numberOfSspStates = numberOfNonComponentStates + this->_longRunComponentDecomposition->size(); uint64_t numberOfSspStates = numberOfNonComponentStates + this->_longRunComponentDecomposition->size();
storm::storage::SparseMatrixBuilder<ValueType> sspMatrixBuilder(0, numberOfSspStates , 0, true, true, numberOfSspStates); storm::storage::SparseMatrixBuilder<ValueType> sspMatrixBuilder(0, numberOfSspStates , 0, true, true, numberOfSspStates);
@ -323,7 +341,7 @@ namespace storm {
} }
return std::make_pair(sspMatrixBuilder.build(currentSspChoice, numberOfSspStates, numberOfSspStates), std::move(rhs)); return std::make_pair(sspMatrixBuilder.build(currentSspChoice, numberOfSspStates, numberOfSspStates), std::move(rhs));
} }
template <typename ValueType> template <typename ValueType>
void SparseNondeterministicInfiniteHorizonHelper<ValueType>::constructOptimalChoices(std::vector<uint64_t> const& sspChoices, storm::storage::SparseMatrix<ValueType> const& sspMatrix, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>> const& sspComponentExitChoicesToOriginalMap) { void SparseNondeterministicInfiniteHorizonHelper<ValueType>::constructOptimalChoices(std::vector<uint64_t> const& sspChoices, storm::storage::SparseMatrix<ValueType> const& sspMatrix, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>> const& sspComponentExitChoicesToOriginalMap) {
// We first take care of non-mec states // We first take care of non-mec states
@ -398,11 +416,11 @@ namespace storm {
template <typename ValueType> template <typename ValueType>
std::vector<ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& componentLraValues) { std::vector<ValueType> SparseNondeterministicInfiniteHorizonHelper<ValueType>::buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& componentLraValues) {
STORM_LOG_ASSERT(this->_longRunComponentDecomposition != nullptr, "Decomposition not computed, yet."); STORM_LOG_ASSERT(this->_longRunComponentDecomposition != nullptr, "Decomposition not computed, yet.");
// For fast transition rewriting, we build a mapping from the input state indices to the state indices of a new transition matrix // For fast transition rewriting, we build a mapping from the input state indices to the state indices of a new transition matrix
// which redirects all transitions leading to a former component state to a new auxiliary state. // which redirects all transitions leading to a former component state to a new auxiliary state.
// There will be one auxiliary state for each component. These states will be appended to the end of the matrix. // There will be one auxiliary state for each component. These states will be appended to the end of the matrix.
// First gather the states that are part of a component // First gather the states that are part of a component
// and create a mapping from states that lie in a component to the corresponding component index. // and create a mapping from states that lie in a component to the corresponding component index.
storm::storage::BitVector statesInComponents(this->_transitionMatrix.getRowGroupCount()); storm::storage::BitVector statesInComponents(this->_transitionMatrix.getRowGroupCount());
@ -427,14 +445,14 @@ namespace storm {
for (auto mecState : statesInComponents) { for (auto mecState : statesInComponents) {
inputToSspStateMap[mecState] += numberOfNonComponentStates; inputToSspStateMap[mecState] += numberOfNonComponentStates;
} }
// For scheduler extraction, we will need to create a mapping between choices at the auxiliary states and the // For scheduler extraction, we will need to create a mapping between choices at the auxiliary states and the
// corresponding choices in the original model. // corresponding choices in the original model.
std::vector<std::pair<uint_fast64_t, uint_fast64_t>> sspComponentExitChoicesToOriginalMap; std::vector<std::pair<uint_fast64_t, uint_fast64_t>> sspComponentExitChoicesToOriginalMap;
// The next step is to create the SSP matrix and the right-hand side of the SSP. // The next step is to create the SSP matrix and the right-hand side of the SSP.
auto sspMatrixVector = buildSspMatrixVector(componentLraValues, inputToSspStateMap, statesNotInComponent, numberOfNonComponentStates, this->isProduceSchedulerSet() ? &sspComponentExitChoicesToOriginalMap : nullptr); auto sspMatrixVector = buildSspMatrixVector(componentLraValues, inputToSspStateMap, statesNotInComponent, numberOfNonComponentStates, this->isProduceSchedulerSet() ? &sspComponentExitChoicesToOriginalMap : nullptr);
// Set-up a solver // Set-up a solver
storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory; storm::solver::GeneralMinMaxLinearEquationSolverFactory<ValueType> minMaxLinearEquationSolverFactory;
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, this->getOptimizationDirection(), false, this->isProduceSchedulerSet()); storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, true, this->getOptimizationDirection(), false, this->isProduceSchedulerSet());
@ -448,7 +466,7 @@ namespace storm {
solver->setLowerBound(*lowerUpperBounds.first); solver->setLowerBound(*lowerUpperBounds.first);
solver->setUpperBound(*lowerUpperBounds.second); solver->setUpperBound(*lowerUpperBounds.second);
solver->setRequirementsChecked(); solver->setRequirementsChecked();
// Solve the equation system // Solve the equation system
std::vector<ValueType> x(sspMatrixVector.first.getRowGroupCount()); std::vector<ValueType> x(sspMatrixVector.first.getRowGroupCount());
solver->solveEquations(env, this->getOptimizationDirection(), x, sspMatrixVector.second); solver->solveEquations(env, this->getOptimizationDirection(), x, sspMatrixVector.second);
@ -460,7 +478,7 @@ namespace storm {
} else { } else {
STORM_LOG_ERROR_COND(!this->isProduceSchedulerSet(), "Requested to produce a scheduler, but no scheduler was generated."); STORM_LOG_ERROR_COND(!this->isProduceSchedulerSet(), "Requested to produce a scheduler, but no scheduler was generated.");
} }
// Prepare result vector. // Prepare result vector.
// For efficiency reasons, we re-use the memory of our rhs for this! // For efficiency reasons, we re-use the memory of our rhs for this!
std::vector<ValueType> result = std::move(sspMatrixVector.second); std::vector<ValueType> result = std::move(sspMatrixVector.second);
@ -469,10 +487,10 @@ namespace storm {
storm::utility::vector::selectVectorValues(result, inputToSspStateMap, x); storm::utility::vector::selectVectorValues(result, inputToSspStateMap, x);
return result; return result;
} }
template class SparseNondeterministicInfiniteHorizonHelper<double>; template class SparseNondeterministicInfiniteHorizonHelper<double>;
template class SparseNondeterministicInfiniteHorizonHelper<storm::RationalNumber>; template class SparseNondeterministicInfiniteHorizonHelper<storm::RationalNumber>;
} }
} }
}
}

43
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h

@ -3,14 +3,14 @@
namespace storm { namespace storm {
namespace storage { namespace storage {
template <typename VT> class Scheduler; template <typename VT> class Scheduler;
} }
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
/*! /*!
* Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system. * Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system.
* @tparam ValueType the type a value can have * @tparam ValueType the type a value can have
@ -23,35 +23,40 @@ namespace storm {
* Function mapping from indices to values * Function mapping from indices to values
*/ */
typedef typename SparseInfiniteHorizonHelper<ValueType, true>::ValueGetter ValueGetter; typedef typename SparseInfiniteHorizonHelper<ValueType, true>::ValueGetter ValueGetter;
/*! /*!
* Initializes the helper for a discrete time model (i.e. MDP) * Initializes the helper for a discrete time model (i.e. MDP)
*/ */
SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix); SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix);
/*! /*!
* Initializes the helper for a continuous time model (i.e. MA) * Initializes the helper for a continuous time model (i.e. MA)
*/ */
SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates); SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector<ValueType> const& exitRates);
/*! /*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled. * @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call. * @return the produced scheduler of the most recent call.
*/ */
std::vector<uint64_t> const& getProducedOptimalChoices() const; std::vector<uint64_t> const& getProducedOptimalChoices() const;
/*! /*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled. * @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call. * @return the produced scheduler of the most recent call.
*/ */
std::vector<uint64_t>& getProducedOptimalChoices(); std::vector<uint64_t>& getProducedOptimalChoices();
/*! /*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled. * @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return a new scheduler containing optimal choices for each state that yield the long run average values of the most recent call. * @return a new scheduler containing optimal choices for each state that yield the long run average values of the most recent call.
*/ */
storm::storage::Scheduler<ValueType> extractScheduler() const; storm::storage::Scheduler<ValueType> extractScheduler() const;
/*!
* @return the computed choice values for the states.
*/
std::vector<ValueType> getChoiceValues() const;
/*! /*!
* @param stateValuesGetter a function returning a value for a given state index * @param stateValuesGetter a function returning a value for a given state index
* @param actionValuesGetter a function returning a value for a given (global) choice index * @param actionValuesGetter a function returning a value for a given (global) choice index
@ -59,43 +64,43 @@ namespace storm {
* @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for the states of the given component which yield the returned LRA value. Choices for states outside of the component are not affected. * @post if scheduler production is enabled and Nondeterministic is true, getProducedOptimalChoices() contains choices for the states of the given component which yield the returned LRA value. Choices for states outside of the component are not affected.
*/ */
virtual ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component) override; virtual ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component) override;
protected: protected:
virtual void createDecomposition() override; virtual void createDecomposition() override;
std::pair<bool, ValueType> computeLraForTrivialMec(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec); std::pair<bool, ValueType> computeLraForTrivialMec(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);
/*! /*!
* As computeLraForMec but uses value iteration as a solution method (independent of what is set in env) * As computeLraForMec but uses value iteration as a solution method (independent of what is set in env)
*/ */
ValueType computeLraForMecVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec); ValueType computeLraForMecVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);
/*! /*!
* As computeLraForMec but uses linear programming as a solution method (independent of what is set in env) * As computeLraForMec but uses linear programming as a solution method (independent of what is set in env)
* @see Guck et al.: Modelling and Analysis of Markov Reward Automata (ATVA'14), https://doi.org/10.1007/978-3-319-11936-6_13 * @see Guck et al.: Modelling and Analysis of Markov Reward Automata (ATVA'14), https://doi.org/10.1007/978-3-319-11936-6_13
*/ */
ValueType computeLraForMecLp(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec); ValueType computeLraForMecLp(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);
std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> buildSspMatrixVector(std::vector<ValueType> const& mecLraValues, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>>* sspComponentExitChoicesToOriginalMap); std::pair<storm::storage::SparseMatrix<ValueType>, std::vector<ValueType>> buildSspMatrixVector(std::vector<ValueType> const& mecLraValues, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>>* sspComponentExitChoicesToOriginalMap);
/*! /*!
* @pre a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components. * @pre a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components.
* Translates optimal choices for MECS and SSP to the original model. * Translates optimal choices for MECS and SSP to the original model.
* @post getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values. * @post getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values.
*/ */
void constructOptimalChoices(std::vector<uint64_t> const& sspChoices, storm::storage::SparseMatrix<ValueType> const& sspMatrix, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>> const& sspComponentExitChoicesToOriginalMap); void constructOptimalChoices(std::vector<uint64_t> const& sspChoices, storm::storage::SparseMatrix<ValueType> const& sspMatrix, std::vector<uint64_t> const& inputToSspStateMap, storm::storage::BitVector const& statesNotInComponent, uint64_t numberOfNonComponentStates, std::vector<std::pair<uint64_t, uint64_t>> const& sspComponentExitChoicesToOriginalMap);
/*! /*!
* @pre if scheduler production is enabled a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components. * @pre if scheduler production is enabled a choice for each state within a component must be set such that the choices yield optimal values w.r.t. the individual components.
* @return Lra values for each state * @return Lra values for each state
* @post if scheduler production is enabled getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values. * @post if scheduler production is enabled getProducedOptimalChoices() contains choices for all input model states which yield the returned LRA values.
*/ */
virtual std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues) override; virtual std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues) override;
}; };
} }
} }
}
}

64
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp

@ -159,7 +159,7 @@ namespace storm {
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType> template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
ValueType LraViHelper<ValueType, ComponentType, TransitionsType>::performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices) {
ValueType LraViHelper<ValueType, ComponentType, TransitionsType>::performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices, std::vector<ValueType>* choiceValues) {
initializeNewValues(stateValueGetter, actionValueGetter, exitRates); initializeNewValues(stateValueGetter, actionValueGetter, exitRates);
ValueType precision = storm::utility::convertNumber<ValueType>(env.solver().lra().getPrecision()); ValueType precision = storm::utility::convertNumber<ValueType>(env.solver().lra().getPrecision());
bool relative = env.solver().lra().getRelativeTerminationCriterion(); bool relative = env.solver().lra().getRelativeTerminationCriterion();
@ -214,16 +214,19 @@ namespace storm {
STORM_LOG_TRACE("LRA computation converged after " << iter << " iterations."); STORM_LOG_TRACE("LRA computation converged after " << iter << " iterations.");
} }
if (choices) {
if (choices || choiceValues) {
// We will be doing one more iteration step and track scheduler choices this time. // We will be doing one more iteration step and track scheduler choices this time.
if(!gameNondetTs()) { if(!gameNondetTs()) {
prepareNextIteration(env); prepareNextIteration(env);
} }
performIterationStep(env, dir, choices);
performIterationStep(env, dir, choices, choiceValues);
} }
if(gameNondetTs()) { if(gameNondetTs()) {
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
result = (xOld().at(0) * _uniformizationRate)/(double)iter; // TODO is "init" always going to be .at(0) ?
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
result = (xOld().at(0) * _uniformizationRate)/(double)iter; // TODO is "init" always going to be .at(0) ?
if(choiceValues) {
storm::utility::vector::applyPointwise<ValueType, ValueType>(*choiceValues, *choiceValues, [this, &iter] (ValueType const& c_i) -> ValueType { return (c_i * _uniformizationRate) / (double)iter; });
}
} }
return result; return result;
} }
@ -358,7 +361,23 @@ namespace storm {
} }
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType> template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices) {
void LraViHelper<ValueType, ComponentType, TransitionsType>::setInputModelChoiceValues(std::vector<ValueType>& choiceValues, std::vector<ValueType> const& localMecChoiceValues) const {
// Transform the local choiceValues (within this mec) to choice values for the input model
uint64_t localState = 0;
uint64_t choiceValuesOffset = 0;
for (auto const& element : _component) {
uint64_t elementState = element.first;
uint64_t rowIndex = _transitionMatrix.getRowGroupIndices()[elementState];
uint64_t rowGroupSize = _transitionMatrix.getRowGroupEntryCount(elementState);
std::copy(localMecChoiceValues.begin() + choiceValuesOffset, localMecChoiceValues.begin() + choiceValuesOffset + rowGroupSize, &choiceValues.at(rowIndex));
localState++;
choiceValuesOffset += rowGroupSize;
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices, std::vector<ValueType>* choiceValues) {
STORM_LOG_ASSERT(!((nondetTs() || nondetIs()) && dir == nullptr), "No optimization direction provided for model with nondeterminism"); STORM_LOG_ASSERT(!((nondetTs() || nondetIs()) && dir == nullptr), "No optimization direction provided for model with nondeterminism");
// Initialize value vectors, multiplers, and solver if this has not been done, yet // Initialize value vectors, multiplers, and solver if this has not been done, yet
if (!_TsMultiplier) { if (!_TsMultiplier) {
@ -373,24 +392,47 @@ namespace storm {
// Compute the values obtained by a single uniformization step between timed states only // Compute the values obtained by a single uniformization step between timed states only
if (nondetTs() && !gameNondetTs()) { if (nondetTs() && !gameNondetTs()) {
if (choices == nullptr) {
if (choices == nullptr && choiceValues == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew()); _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
} else { } else {
// Also keep track of the choices made. // Also keep track of the choices made.
std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount()); std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount());
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices);
std::vector<ValueType> resultChoiceValues(_TsTransitions.getRowCount());
_TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, resultChoiceValues);
auto rowGroupIndices = this->_TsTransitions.getRowGroupIndices();
rowGroupIndices.erase(rowGroupIndices.begin());
_TsMultiplier->reduce(env, *dir, rowGroupIndices, resultChoiceValues, xNew(), &tsChoices);
// Note that nondeterminism within the timed states means that there can not be instant states (We either have MDPs or MAs) // Note that nondeterminism within the timed states means that there can not be instant states (We either have MDPs or MAs)
// Hence, in this branch we don't have to care for choices at instant states. // Hence, in this branch we don't have to care for choices at instant states.
STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states."); STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states.");
setInputModelChoices(*choices, tsChoices);
if(choices != nullptr) {
setInputModelChoices(*choices, tsChoices);
}
if(choiceValues != nullptr) {
setInputModelChoiceValues(*choiceValues, resultChoiceValues);
}
} }
} else if(gameNondetTs()) { // TODO DRYness? exact same behaviour as case above? } else if(gameNondetTs()) { // TODO DRYness? exact same behaviour as case above?
if (choices == nullptr) { if (choices == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), nullptr, _statesOfCoalition); _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), nullptr, _statesOfCoalition);
} else { } else {
// Also keep track of the choices made.
std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount()); std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount());
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices, _statesOfCoalition);
setInputModelChoices(*choices, tsChoices); // no components -> no need for that call?
std::vector<ValueType> resultChoiceValues(_TsTransitions.getRowCount());
_TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, resultChoiceValues);
auto rowGroupIndices = this->_TsTransitions.getRowGroupIndices();
rowGroupIndices.erase(rowGroupIndices.begin());
_TsMultiplier->reduce(env, *dir, rowGroupIndices, resultChoiceValues, xNew(), &tsChoices);
if(choices != nullptr) {
setInputModelChoices(*choices, tsChoices); // no components -> no need for that call?
}
if(choiceValues != nullptr) {
setInputModelChoiceValues(*choiceValues, resultChoiceValues);
}
} }
} else { } else {
_TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew()); _TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew());

6
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h

@ -68,7 +68,7 @@ namespace storm {
* @return The (optimal) long run average value of the specified component. * @return The (optimal) long run average value of the specified component.
* @note it is possible to call this method multiple times with different values. However, other changes to the environment or the optimization direction might not have the expected effect due to caching. * @note it is possible to call this method multiple times with different values. However, other changes to the environment or the optimization direction might not have the expected effect due to caching.
*/ */
ValueType performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates = nullptr, storm::solver::OptimizationDirection const* dir = nullptr, std::vector<uint64_t>* choices = nullptr);
ValueType performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates = nullptr, storm::solver::OptimizationDirection const* dir = nullptr, std::vector<uint64_t>* choices = nullptr, std::vector<ValueType>* choiceValues = nullptr);
private: private:
@ -89,7 +89,7 @@ namespace storm {
* Note that these choices will be inserted w.r.t. the original model states/choices, i.e. the size of the vector should match the state-count of the input model * Note that these choices will be inserted w.r.t. the original model states/choices, i.e. the size of the vector should match the state-count of the input model
* @pre when calling this the first time, initializeNewValues must have been called before. Moreover, prepareNextIteration must be called between two calls of this. * @pre when calling this the first time, initializeNewValues must have been called before. Moreover, prepareNextIteration must be called between two calls of this.
*/ */
void performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir = nullptr, std::vector<uint64_t>* choices = nullptr);
void performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir = nullptr, std::vector<uint64_t>* choices = nullptr, std::vector<ValueType>* choiceValues = nullptr);
struct ConvergenceCheckResult { struct ConvergenceCheckResult {
bool isPrecisionAchieved; bool isPrecisionAchieved;
@ -111,6 +111,8 @@ namespace storm {
void setInputModelChoices(std::vector<uint64_t>& choices, std::vector<uint64_t> const& localMecChoices, bool setChoiceZeroToMarkovianStates = false, bool setChoiceZeroToProbabilisticStates = false) const; void setInputModelChoices(std::vector<uint64_t>& choices, std::vector<uint64_t> const& localMecChoices, bool setChoiceZeroToMarkovianStates = false, bool setChoiceZeroToProbabilisticStates = false) const;
void setInputModelChoiceValues(std::vector<ValueType>& choiceValues, std::vector<ValueType> const& localMecChoiceValues) const;
/// Returns true iff the given state is a timed state /// Returns true iff the given state is a timed state
bool isTimedState(uint64_t const& inputModelStateIndex) const; bool isTimedState(uint64_t const& inputModelStateIndex) const;

9
src/storm/modelchecker/helper/utility/SetInformationFromCheckTask.h

@ -5,7 +5,7 @@
namespace storm { namespace storm {
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
/*! /*!
* Forwards relevant information stored in the given CheckTask to the given helper * Forwards relevant information stored in the given CheckTask to the given helper
*/ */
@ -26,10 +26,13 @@ namespace storm {
// Scheduler Production // Scheduler Production
helper.setProduceScheduler(checkTask.isProduceSchedulersSet()); helper.setProduceScheduler(checkTask.isProduceSchedulersSet());
// Shield Synthesis
helper.setProduceChoiceValues(checkTask.isShieldingTask());
// Qualitative flag // Qualitative flag
helper.setQualitative(checkTask.isQualitativeSet()); helper.setQualitative(checkTask.isQualitativeSet());
} }
/*! /*!
* Forwards relevant information stored in the given CheckTask to the given helper * Forwards relevant information stored in the given CheckTask to the given helper
*/ */
@ -50,4 +53,4 @@ namespace storm {
} }
} }
} }
}
}

5
src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp

@ -298,7 +298,10 @@ namespace storm {
auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector()); auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values)));
if (checkTask.isProduceSchedulersSet()) {
if(checkTask.isShieldingTask()) {
storm::storage::BitVector allStatesBv = storm::storage::BitVector(this->getModel().getTransitionMatrix().getRowGroupCount(), true);
tempest::shields::createQuantitativeShield<ValueType>(std::make_shared<storm::models::sparse::Mdp<ValueType>>(this->getModel()), helper.getChoiceValues(), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), allStatesBv, allStatesBv);
} else if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler())); result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler()));
} }
return result; return result;

2
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp

@ -146,7 +146,7 @@ namespace storm {
if(goal.isShieldingTask()) { if(goal.isShieldingTask()) {
multiplier->multiply(env, result, nullptr, choiceValues); multiplier->multiply(env, result, nullptr, choiceValues);
multiplier->reduce(env, goal.direction(), choiceValues, transitionMatrix.getRowGroupIndices(), result, nullptr);
multiplier->reduce(env, goal.direction(), transitionMatrix.getRowGroupIndices(), choiceValues, result);
} }
else { else {
multiplier->multiplyAndReduce(env, dir, result, nullptr, result); multiplier->multiplyAndReduce(env, dir, result, nullptr, result);

14
src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp

@ -144,7 +144,8 @@ namespace storm {
auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint()); auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values)));
if(checkTask.isShieldingTask()) { if(checkTask.isShieldingTask()) {
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), std::move(ret.relevantStates), ~statesOfCoalition);
storm::storage::BitVector allStatesBv = storm::storage::BitVector(this->getModel().getTransitionMatrix().getRowGroupCount(), true);
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), allStatesBv, ~statesOfCoalition);
} else if (checkTask.isProduceSchedulersSet() && ret.scheduler) { } else if (checkTask.isProduceSchedulersSet() && ret.scheduler) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::move(ret.scheduler)); result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::move(ret.scheduler));
} }
@ -160,7 +161,8 @@ namespace storm {
auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeGloballyProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint()); auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeGloballyProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values)));
if(checkTask.isShieldingTask()) { if(checkTask.isShieldingTask()) {
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), std::move(ret.relevantStates), ~statesOfCoalition);
storm::storage::BitVector allStatesBv = storm::storage::BitVector(this->getModel().getTransitionMatrix().getRowGroupCount(), true);
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), allStatesBv, ~statesOfCoalition);
} else if (checkTask.isProduceSchedulersSet() && ret.scheduler) { } else if (checkTask.isProduceSchedulersSet() && ret.scheduler) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::move(ret.scheduler)); result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::move(ret.scheduler));
} }
@ -194,7 +196,8 @@ namespace storm {
auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeBoundedGloballyProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint(), pathFormula.getNonStrictLowerBound<uint64_t>(), pathFormula.getNonStrictUpperBound<uint64_t>()); auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeBoundedGloballyProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint(), pathFormula.getNonStrictLowerBound<uint64_t>(), pathFormula.getNonStrictUpperBound<uint64_t>());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values)));
if(checkTask.isShieldingTask()) { if(checkTask.isShieldingTask()) {
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), std::move(ret.relevantStates), ~statesOfCoalition);
storm::storage::BitVector allStatesBv = storm::storage::BitVector(this->getModel().getTransitionMatrix().getRowGroupCount(), true);
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), allStatesBv, ~statesOfCoalition);
} }
return result; return result;
} }
@ -216,7 +219,7 @@ namespace storm {
auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint(), pathFormula.getNonStrictLowerBound<uint64_t>(), pathFormula.getNonStrictUpperBound<uint64_t>()); auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper<ValueType>::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint(), pathFormula.getNonStrictLowerBound<uint64_t>(), pathFormula.getNonStrictUpperBound<uint64_t>());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(ret.values)));
if(checkTask.isShieldingTask()) { if(checkTask.isShieldingTask()) {
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), std::move(ret.relevantStates), ~statesOfCoalition);
tempest::shields::createShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), std::move(ret.choiceValues), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), std::move(ret.relevantStates), ~statesOfCoalition);
} }
return result; return result;
} }
@ -235,7 +238,8 @@ namespace storm {
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values)));
if(checkTask.isShieldingTask()) { if(checkTask.isShieldingTask()) {
tempest::shields::createQuantitativeShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), helper.getProducedOptimalChoices(), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), statesOfCoalition, statesOfCoalition);
storm::storage::BitVector allStatesBv = storm::storage::BitVector(this->getModel().getTransitionMatrix().getRowGroupCount(), true);
tempest::shields::createQuantitativeShield<ValueType>(std::make_shared<storm::models::sparse::Smg<ValueType>>(this->getModel()), helper.getChoiceValues(), checkTask.getShieldingExpression(), checkTask.getOptimizationDirection(), allStatesBv, statesOfCoalition);
} else if (checkTask.isProduceSchedulersSet()) { } else if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler())); result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler()));
} }

2
src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp

@ -112,7 +112,7 @@ namespace storm {
auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix); auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix);
auto rowGroupIndices = transitionMatrix.getRowGroupIndices(); auto rowGroupIndices = transitionMatrix.getRowGroupIndices();
rowGroupIndices.erase(rowGroupIndices.begin()); rowGroupIndices.erase(rowGroupIndices.begin());
multiplier->reduce(env, goal.direction(), b, rowGroupIndices, result, &statesOfCoalition);
multiplier->reduce(env, goal.direction(), rowGroupIndices, b, result, nullptr, &statesOfCoalition);
if (goal.isShieldingTask()) { if (goal.isShieldingTask()) {
choiceValues = b; choiceValues = b;
} }

12
src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp

@ -50,7 +50,7 @@ namespace storm {
_multiplier->multiply(env, xNew(), &_b, constrainedChoiceValues); _multiplier->multiply(env, xNew(), &_b, constrainedChoiceValues);
auto rowGroupIndices = this->_transitionMatrix.getRowGroupIndices(); auto rowGroupIndices = this->_transitionMatrix.getRowGroupIndices();
rowGroupIndices.erase(rowGroupIndices.begin()); rowGroupIndices.erase(rowGroupIndices.begin());
_multiplier->reduce(env, dir, constrainedChoiceValues, rowGroupIndices, xNew());
_multiplier->reduce(env, dir, rowGroupIndices, constrainedChoiceValues, xNew(), nullptr, &_statesOfCoalition);
break; break;
} }
performIterationStep(env, dir); performIterationStep(env, dir);
@ -125,6 +125,16 @@ namespace storm {
return _produceScheduler; return _produceScheduler;
} }
template <typename ValueType>
void GameViHelper<ValueType>::setShieldingTask(bool value) {
_shieldingTask = value;
}
template <typename ValueType>
bool GameViHelper<ValueType>::isShieldingTask() const {
return _shieldingTask;
}
template <typename ValueType> template <typename ValueType>
void GameViHelper<ValueType>::updateTransitionMatrix(storm::storage::SparseMatrix<ValueType> newTransitionMatrix) { void GameViHelper<ValueType>::updateTransitionMatrix(storm::storage::SparseMatrix<ValueType> newTransitionMatrix) {
_transitionMatrix = newTransitionMatrix; _transitionMatrix = newTransitionMatrix;

11
src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h

@ -38,6 +38,16 @@ namespace storm {
*/ */
bool isProduceSchedulerSet() const; bool isProduceSchedulerSet() const;
/*!
* Sets whether an optimal scheduler shall be constructed during the computation
*/
void setShieldingTask(bool value);
/*!
* @return whether an optimal scheduler shall be constructed during the computation
*/
bool isShieldingTask() const;
/*! /*!
* Changes the transitionMatrix to the given one. * Changes the transitionMatrix to the given one.
*/ */
@ -93,6 +103,7 @@ namespace storm {
std::unique_ptr<storm::solver::Multiplier<ValueType>> _multiplier; std::unique_ptr<storm::solver::Multiplier<ValueType>> _multiplier;
bool _produceScheduler = false; bool _produceScheduler = false;
bool _shieldingTask = false;
boost::optional<std::vector<uint64_t>> _producedOptimalChoices; boost::optional<std::vector<uint64_t>> _producedOptimalChoices;
}; };
} }

8
src/storm/shields/AbstractShield.h

@ -21,9 +21,13 @@ namespace tempest {
namespace utility { namespace utility {
template<typename ValueType, typename Compare, bool relative> template<typename ValueType, typename Compare, bool relative>
struct ChoiceFilter { struct ChoiceFilter {
bool operator()(ValueType v, ValueType max, double shieldValue) {
bool operator()(ValueType v, ValueType opt, double shieldValue) {
Compare compare; Compare compare;
if(relative) return compare(v, max * shieldValue);
if(relative && std::is_same<Compare, storm::utility::ElementLessEqual<ValueType>>::value) {
return compare(v, opt + opt * shieldValue);
} else if(relative && std::is_same<Compare, storm::utility::ElementGreaterEqual<ValueType>>::value) {
return compare(v, opt * shieldValue);
}
else return compare(v, shieldValue); else return compare(v, shieldValue);
} }
}; };

54
src/storm/shields/OptimalShield.cpp

@ -6,27 +6,65 @@ namespace tempest {
namespace shields { namespace shields {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
OptimalShield<ValueType, IndexType>::OptimalShield(std::vector<IndexType> const& rowGroupIndices, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), precomputedChoices(precomputedChoices) {
OptimalShield<ValueType, IndexType>::OptimalShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), choiceValues(choiceValues) {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
storm::storage::OptimalScheduler<ValueType> OptimalShield<ValueType, IndexType>::construct() {
storm::storage::OptimalScheduler<ValueType> shield(this->rowGroupIndices.size() - 1);
// TODO Needs fixing as soon as we support MDPs
storm::storage::PostScheduler<ValueType> OptimalShield<ValueType, IndexType>::construct() {
if (this->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
if(this->shieldingExpression->isRelative()) {
return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, true>();
} else {
return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, false>();
}
} else {
if(this->shieldingExpression->isRelative()) {
return constructWithCompareType<storm::utility::ElementGreaterEqual<ValueType>, true>();
} else {
return constructWithCompareType<storm::utility::ElementGreaterEqual<ValueType>, false>();
}
}
}
template<typename ValueType, typename IndexType>
template<typename Compare, bool relative>
storm::storage::PostScheduler<ValueType> OptimalShield<ValueType, IndexType>::constructWithCompareType() {
tempest::shields::utility::ChoiceFilter<ValueType, Compare, relative> choiceFilter;
storm::storage::PostScheduler<ValueType> shield(this->rowGroupIndices.size() - 1, this->computeRowGroupSizes());
auto choice_it = this->choiceValues.begin();
if(this->coalitionStates.is_initialized()) { if(this->coalitionStates.is_initialized()) {
this->relevantStates = ~this->relevantStates;
this->relevantStates &= this->coalitionStates.get();
} }
for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) { for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) {
uint rowGroupSize = this->rowGroupIndices[state + 1] - this->rowGroupIndices[state];
if(this->relevantStates.get(state)) { if(this->relevantStates.get(state)) {
shield.setChoice(precomputedChoices[state], state);
auto maxProbabilityIndex = std::max_element(choice_it, choice_it + rowGroupSize) - choice_it;
ValueType maxProbability = *(choice_it + maxProbabilityIndex);
if(!relative && !choiceFilter(maxProbability, maxProbability, this->shieldingExpression->getValue())) {
STORM_LOG_WARN("No shielding action possible with absolute comparison for state with index " << state);
shield.setChoice(storm::storage::PostSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize;
continue;
}
storm::storage::PostSchedulerChoice<ValueType> choiceMapping;
for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) {
if(choiceFilter(*choice_it, maxProbability, this->shieldingExpression->getValue())) {
choiceMapping.addChoice(choice, choice);
} else {
choiceMapping.addChoice(choice, maxProbabilityIndex);
}
}
shield.setChoice(choiceMapping, state, 0);
} else { } else {
shield.setChoice(storm::storage::Distribution<ValueType, IndexType>(), state);
shield.setChoice(storm::storage::PostSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize;
} }
} }
return shield; return shield;
} }
// Explicitly instantiate appropriate
// Explicitly instantiate appropriate classes
template class OptimalShield<double, typename storm::storage::SparseMatrix<double>::index_type>; template class OptimalShield<double, typename storm::storage::SparseMatrix<double>::index_type>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class OptimalShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>; template class OptimalShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>;

10
src/storm/shields/OptimalShield.h

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "storm/shields/AbstractShield.h" #include "storm/shields/AbstractShield.h"
#include "storm/storage/OptimalScheduler.h"
#include "storm/storage/PostScheduler.h"
namespace tempest { namespace tempest {
namespace shields { namespace shields {
@ -9,11 +9,13 @@ namespace tempest {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
class OptimalShield : public AbstractShield<ValueType, IndexType> { class OptimalShield : public AbstractShield<ValueType, IndexType> {
public: public:
OptimalShield(std::vector<IndexType> const& rowGroupIndices, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
OptimalShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
storm::storage::OptimalScheduler<ValueType> construct();
storm::storage::PostScheduler<ValueType> construct();
template<typename Compare, bool relative>
storm::storage::PostScheduler<ValueType> constructWithCompareType();
private: private:
std::vector<uint64_t> precomputedChoices;
std::vector<ValueType> choiceValues;
}; };
} }
} }

39
src/storm/shields/PostSafetyShield.cpp → src/storm/shields/PostShield.cpp

@ -1,4 +1,4 @@
#include "storm/shields/PostSafetyShield.h"
#include "storm/shields/PostShield.h"
#include <algorithm> #include <algorithm>
@ -6,12 +6,12 @@ namespace tempest {
namespace shields { namespace shields {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
PostSafetyShield<ValueType, IndexType>::PostSafetyShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), choiceValues(choiceValues) {
PostShield<ValueType, IndexType>::PostShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), choiceValues(choiceValues) {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
storm::storage::PostScheduler<ValueType> PostSafetyShield<ValueType, IndexType>::construct() {
storm::storage::PostScheduler<ValueType> PostShield<ValueType, IndexType>::construct() {
if (this->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { if (this->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
if(this->shieldingExpression->isRelative()) { if(this->shieldingExpression->isRelative()) {
return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, true>(); return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, true>();
@ -29,45 +29,48 @@ namespace tempest {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
template<typename Compare, bool relative> template<typename Compare, bool relative>
storm::storage::PostScheduler<ValueType> PostSafetyShield<ValueType, IndexType>::constructWithCompareType() {
storm::storage::PostScheduler<ValueType> PostShield<ValueType, IndexType>::constructWithCompareType() {
tempest::shields::utility::ChoiceFilter<ValueType, Compare, relative> choiceFilter; tempest::shields::utility::ChoiceFilter<ValueType, Compare, relative> choiceFilter;
storm::storage::PostScheduler<ValueType> shield(this->rowGroupIndices.size() - 1, this->computeRowGroupSizes()); storm::storage::PostScheduler<ValueType> shield(this->rowGroupIndices.size() - 1, this->computeRowGroupSizes());
auto choice_it = this->choiceValues.begin(); auto choice_it = this->choiceValues.begin();
if(this->coalitionStates.is_initialized()) { if(this->coalitionStates.is_initialized()) {
this->relevantStates &= this->coalitionStates.get();
this->relevantStates &= ~this->coalitionStates.get();
} }
for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) { for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) {
uint rowGroupSize = this->rowGroupIndices[state + 1] - this->rowGroupIndices[state]; uint rowGroupSize = this->rowGroupIndices[state + 1] - this->rowGroupIndices[state];
if(this->relevantStates.get(state)) { if(this->relevantStates.get(state)) {
auto maxProbabilityIndex = std::max_element(choice_it, choice_it + rowGroupSize) - choice_it;
ValueType maxProbability = *(choice_it + maxProbabilityIndex);
if(!relative && !choiceFilter(maxProbability, maxProbability, this->shieldingExpression->getValue())) {
auto optProbabilityIndex = std::min_element(choice_it, choice_it + rowGroupSize) - choice_it;
if(std::is_same<Compare, storm::utility::ElementGreaterEqual<ValueType>>::value) {
optProbabilityIndex = std::max_element(choice_it, choice_it + rowGroupSize) - choice_it;
}
ValueType optProbability = *(choice_it + optProbabilityIndex);
if(!relative && !choiceFilter(optProbability, optProbability, this->shieldingExpression->getValue())) {
STORM_LOG_WARN("No shielding action possible with absolute comparison for state with index " << state); STORM_LOG_WARN("No shielding action possible with absolute comparison for state with index " << state);
shield.setChoice(0, storm::storage::Distribution<ValueType, IndexType>(), state);
shield.setChoice(storm::storage::PostSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize; choice_it += rowGroupSize;
continue; continue;
} }
storm::storage::PostSchedulerChoice<ValueType> choiceMapping;
for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) { for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) {
storm::storage::Distribution<ValueType, IndexType> actionDistribution;
if(choiceFilter(*choice_it, maxProbability, this->shieldingExpression->getValue())) {
actionDistribution.addProbability(choice, 1);
if(choiceFilter(*choice_it, optProbability, this->shieldingExpression->getValue())) {
choiceMapping.addChoice(choice, choice);
} else { } else {
actionDistribution.addProbability(maxProbabilityIndex, 1);
choiceMapping.addChoice(choice, optProbabilityIndex);
} }
shield.setChoice(choice, storm::storage::SchedulerChoice<ValueType>(actionDistribution), state);
} }
shield.setChoice(choiceMapping, state, 0);
} else { } else {
shield.setChoice(0, storm::storage::Distribution<ValueType, IndexType>(), state);
shield.setChoice(storm::storage::PostSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize; choice_it += rowGroupSize;
} }
} }
return shield; return shield;
} }
// Explicitly instantiate appropriate
template class PostSafetyShield<double, typename storm::storage::SparseMatrix<double>::index_type>;
// Explicitly instantiate appropriate classes
template class PostShield<double, typename storm::storage::SparseMatrix<double>::index_type>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class PostSafetyShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>;
template class PostShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>;
#endif #endif
} }
} }

4
src/storm/shields/PostSafetyShield.h → src/storm/shields/PostShield.h

@ -7,9 +7,9 @@ namespace tempest {
namespace shields { namespace shields {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
class PostSafetyShield : public AbstractShield<ValueType, IndexType> {
class PostShield : public AbstractShield<ValueType, IndexType> {
public: public:
PostSafetyShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
PostShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
storm::storage::PostScheduler<ValueType> construct(); storm::storage::PostScheduler<ValueType> construct();
template<typename Compare, bool relative> template<typename Compare, bool relative>

38
src/storm/shields/PreSafetyShield.cpp → src/storm/shields/PreShield.cpp

@ -1,4 +1,4 @@
#include "storm/shields/PreSafetyShield.h"
#include "storm/shields/PreShield.h"
#include <algorithm> #include <algorithm>
@ -6,12 +6,12 @@ namespace tempest {
namespace shields { namespace shields {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
PreSafetyShield<ValueType, IndexType>::PreSafetyShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), choiceValues(choiceValues) {
PreShield<ValueType, IndexType>::PreShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) : AbstractShield<ValueType, IndexType>(rowGroupIndices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates), choiceValues(choiceValues) {
// Intentionally left empty. // Intentionally left empty.
} }
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
storm::storage::PreScheduler<ValueType> PreSafetyShield<ValueType, IndexType>::construct() {
storm::storage::PreScheduler<ValueType> PreShield<ValueType, IndexType>::construct() {
if (this->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { if (this->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
if(this->shieldingExpression->isRelative()) { if(this->shieldingExpression->isRelative()) {
return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, true>(); return constructWithCompareType<storm::utility::ElementLessEqual<ValueType>, true>();
@ -29,42 +29,48 @@ namespace tempest {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
template<typename Compare, bool relative> template<typename Compare, bool relative>
storm::storage::PreScheduler<ValueType> PreSafetyShield<ValueType, IndexType>::constructWithCompareType() {
storm::storage::PreScheduler<ValueType> PreShield<ValueType, IndexType>::constructWithCompareType() {
tempest::shields::utility::ChoiceFilter<ValueType, Compare, relative> choiceFilter; tempest::shields::utility::ChoiceFilter<ValueType, Compare, relative> choiceFilter;
storm::storage::PreScheduler<ValueType> shield(this->rowGroupIndices.size() - 1); storm::storage::PreScheduler<ValueType> shield(this->rowGroupIndices.size() - 1);
auto choice_it = this->choiceValues.begin(); auto choice_it = this->choiceValues.begin();
if(this->coalitionStates.is_initialized()) { if(this->coalitionStates.is_initialized()) {
this->relevantStates &= this->coalitionStates.get();
this->relevantStates &= ~this->coalitionStates.get();
} }
for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) { for(uint state = 0; state < this->rowGroupIndices.size() - 1; state++) {
uint rowGroupSize = this->rowGroupIndices[state + 1] - this->rowGroupIndices[state]; uint rowGroupSize = this->rowGroupIndices[state + 1] - this->rowGroupIndices[state];
if(this->relevantStates.get(state)) { if(this->relevantStates.get(state)) {
storm::storage::Distribution<ValueType, IndexType> actionDistribution;
ValueType maxProbability = *std::max_element(choice_it, choice_it + rowGroupSize);
if(!relative && !choiceFilter(maxProbability, maxProbability, this->shieldingExpression->getValue())) {
storm::storage::PreSchedulerChoice<ValueType> enabledChoices;
ValueType optProbability;
if(std::is_same<Compare, storm::utility::ElementGreaterEqual<ValueType>>::value) {
optProbability = *std::max_element(choice_it, choice_it + rowGroupSize);
} else {
optProbability = *std::min_element(choice_it, choice_it + rowGroupSize);
}
if(!relative && !choiceFilter(optProbability, optProbability, this->shieldingExpression->getValue())) {
STORM_LOG_WARN("No shielding action possible with absolute comparison for state with index " << state); STORM_LOG_WARN("No shielding action possible with absolute comparison for state with index " << state);
shield.setChoice(storm::storage::Distribution<ValueType, IndexType>(), state);
shield.setChoice(storm::storage::PreSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize; choice_it += rowGroupSize;
continue; continue;
} }
for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) { for(uint choice = 0; choice < rowGroupSize; choice++, choice_it++) {
if(choiceFilter(*choice_it, maxProbability, this->shieldingExpression->getValue())) {
actionDistribution.addProbability(choice, *choice_it);
if(choiceFilter(*choice_it, optProbability, this->shieldingExpression->getValue())) {
enabledChoices.addChoice(choice, *choice_it);
} }
} }
shield.setChoice(storm::storage::SchedulerChoice<ValueType>(actionDistribution), state);
shield.setChoice(enabledChoices, state, 0);
} else { } else {
shield.setChoice(storm::storage::Distribution<ValueType, IndexType>(), state);
shield.setChoice(storm::storage::PreSchedulerChoice<ValueType>(), state, 0);
choice_it += rowGroupSize; choice_it += rowGroupSize;
} }
} }
return shield; return shield;
} }
// Explicitly instantiate appropriate
template class PreSafetyShield<double, typename storm::storage::SparseMatrix<double>::index_type>;
// Explicitly instantiate appropriate classes
template class PreShield<double, typename storm::storage::SparseMatrix<double>::index_type>;
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template class PreSafetyShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>;
template class PreShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>;
#endif #endif
} }
} }

4
src/storm/shields/PreSafetyShield.h → src/storm/shields/PreShield.h

@ -7,9 +7,9 @@ namespace tempest {
namespace shields { namespace shields {
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
class PreSafetyShield : public AbstractShield<ValueType, IndexType> {
class PreShield : public AbstractShield<ValueType, IndexType> {
public: public:
PreSafetyShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
PreShield(std::vector<IndexType> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
storm::storage::PreScheduler<ValueType> construct(); storm::storage::PreScheduler<ValueType> construct();
template<typename Compare, bool relative> template<typename Compare, bool relative>

19
src/storm/shields/ShieldHandling.cpp

@ -10,11 +10,12 @@ namespace tempest {
void createShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) { void createShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) {
std::ofstream stream; std::ofstream stream;
storm::utility::openFile(shieldFilename(shieldingExpression), stream); storm::utility::openFile(shieldFilename(shieldingExpression), stream);
if(coalitionStates.is_initialized()) coalitionStates.get().complement();
if(shieldingExpression->isPreSafetyShield()) { if(shieldingExpression->isPreSafetyShield()) {
PreSafetyShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
PreShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
shield.construct().printToStream(stream, shieldingExpression, model); shield.construct().printToStream(stream, shieldingExpression, model);
} else if(shieldingExpression->isPostSafetyShield()) { } else if(shieldingExpression->isPostSafetyShield()) {
PostSafetyShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
PostShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
shield.construct().printToStream(stream, shieldingExpression, model); shield.construct().printToStream(stream, shieldingExpression, model);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unknown Shielding Type: " + shieldingExpression->typeToString()); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unknown Shielding Type: " + shieldingExpression->typeToString());
@ -24,11 +25,15 @@ namespace tempest {
} }
template<typename ValueType, typename IndexType> template<typename ValueType, typename IndexType>
void createQuantitativeShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) {
void createQuantitativeShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates) {
std::ofstream stream; std::ofstream stream;
storm::utility::openFile(shieldFilename(shieldingExpression), stream); storm::utility::openFile(shieldFilename(shieldingExpression), stream);
if(shieldingExpression->isOptimalShield()) {
OptimalShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), precomputedChoices, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
if(coalitionStates.is_initialized()) coalitionStates.get().complement(); // TODO CHECK THIS!!!
if(shieldingExpression->isOptimalPreShield()) {
PreShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
shield.construct().printToStream(stream, shieldingExpression, model);
} else if(shieldingExpression->isOptimalPostShield()) {
PostShield<ValueType, IndexType> shield(model->getTransitionMatrix().getRowGroupIndices(), choiceValues, shieldingExpression, optimizationDirection, relevantStates, coalitionStates);
shield.construct().printToStream(stream, shieldingExpression, model); shield.construct().printToStream(stream, shieldingExpression, model);
} else { } else {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unknown Shielding Type: " + shieldingExpression->typeToString()); STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unknown Shielding Type: " + shieldingExpression->typeToString());
@ -38,10 +43,10 @@ namespace tempest {
} }
// Explicitly instantiate appropriate // Explicitly instantiate appropriate
template void createShield<double, typename storm::storage::SparseMatrix<double>::index_type>(std::shared_ptr<storm::models::sparse::Model<double>> model, std::vector<double> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates); template void createShield<double, typename storm::storage::SparseMatrix<double>::index_type>(std::shared_ptr<storm::models::sparse::Model<double>> model, std::vector<double> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
template void createQuantitativeShield<double, typename storm::storage::SparseMatrix<double>::index_type>(std::shared_ptr<storm::models::sparse::Model<double>> model, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
template void createQuantitativeShield<double, typename storm::storage::SparseMatrix<double>::index_type>(std::shared_ptr<storm::models::sparse::Model<double>> model, std::vector<double> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
#ifdef STORM_HAVE_CARL #ifdef STORM_HAVE_CARL
template void createShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> model, std::vector<storm::RationalNumber> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates); template void createShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> model, std::vector<storm::RationalNumber> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
template void createQuantitativeShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> model, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
template void createQuantitativeShield<storm::RationalNumber, typename storm::storage::SparseMatrix<storm::RationalNumber>::index_type>(std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> model, std::vector<storm::RationalNumber> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
#endif #endif
} }
} }

6
src/storm/shields/ShieldHandling.h

@ -10,8 +10,8 @@
#include "storm/logic/ShieldExpression.h" #include "storm/logic/ShieldExpression.h"
#include "storm/shields/AbstractShield.h" #include "storm/shields/AbstractShield.h"
#include "storm/shields/PreSafetyShield.h"
#include "storm/shields/PostSafetyShield.h"
#include "storm/shields/PreShield.h"
#include "storm/shields/PostShield.h"
#include "storm/shields/OptimalShield.h" #include "storm/shields/OptimalShield.h"
#include "storm/io/file.h" #include "storm/io/file.h"
@ -27,6 +27,6 @@ namespace tempest {
void createShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates); void createShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
template<typename ValueType, typename IndexType = storm::storage::sparse::state_type> template<typename ValueType, typename IndexType = storm::storage::sparse::state_type>
void createQuantitativeShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<uint64_t> const& precomputedChoices, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
void createQuantitativeShield(std::shared_ptr<storm::models::sparse::Model<ValueType>> model, std::vector<ValueType> const& choiceValues, std::shared_ptr<storm::logic::ShieldExpression const> const& shieldingExpression, storm::OptimizationDirection optimizationDirection, storm::storage::BitVector relevantStates, boost::optional<storm::storage::BitVector> coalitionStates);
} }
} }

29
src/storm/solver/Multiplier.cpp

@ -75,7 +75,7 @@ namespace storm {
progress.startNewMeasurement(0); progress.startNewMeasurement(0);
for (uint64_t i = 0; i < n; ++i) { for (uint64_t i = 0; i < n; ++i) {
multiply(env, x, b, choiceValues); multiply(env, x, b, choiceValues);
reduce(env, dir, choiceValues, rowGroupIndices, x);
reduce(env, dir, rowGroupIndices, choiceValues, x);
if (storm::utility::resources::isTerminate()) { if (storm::utility::resources::isTerminate()) {
STORM_LOG_WARN("Aborting after " << i << " of " << n << " multiplications"); STORM_LOG_WARN("Aborting after " << i << " of " << n << " multiplications");
break; break;
@ -90,33 +90,34 @@ namespace storm {
} }
template<typename ValueType> template<typename ValueType>
void Multiplier<ValueType>::reduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType> const& choiceValues, std::vector<storm::storage::SparseMatrix<double>::index_type> rowGroupIndices, std::vector<ValueType>& result, storm::storage::BitVector const* dirOverride) const {
auto choice_it = choiceValues.begin();
void Multiplier<ValueType>::reduce(Environment const& env, OptimizationDirection const& dir, std::vector<storm::storage::SparseMatrix<double>::index_type> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices, storm::storage::BitVector const* dirOverride) const {
auto choiceValue_it = choiceValues.begin();
auto optChoice_it = choiceValues.begin();
for(uint state = 0; state < rowGroupIndices.size(); state++) { for(uint state = 0; state < rowGroupIndices.size(); state++) {
uint rowGroupSize; uint rowGroupSize;
if(state == 0) { if(state == 0) {
rowGroupSize = rowGroupIndices[state]; rowGroupSize = rowGroupIndices[state];
} else { } else {
rowGroupSize = rowGroupIndices[state] - rowGroupIndices[state-1];
rowGroupSize = rowGroupIndices[state] - rowGroupIndices[state - 1];
} }
if(dirOverride != nullptr) { if(dirOverride != nullptr) {
if((dir == storm::OptimizationDirection::Minimize && !dirOverride->get(state)) || (dir == storm::OptimizationDirection::Maximize && dirOverride->get(state))) { if((dir == storm::OptimizationDirection::Minimize && !dirOverride->get(state)) || (dir == storm::OptimizationDirection::Maximize && dirOverride->get(state))) {
result.at(state) = *std::min_element(choice_it, choice_it + rowGroupSize);
choice_it += rowGroupSize;
}
else {
result.at(state) = *std::max_element(choice_it, choice_it + rowGroupSize);
choice_it += rowGroupSize;
optChoice_it = std::min_element(choiceValue_it, choiceValue_it + rowGroupSize);
} else {
optChoice_it = std::max_element(choiceValue_it, choiceValue_it + rowGroupSize);
} }
} else { } else {
if(dir == storm::OptimizationDirection::Minimize) { if(dir == storm::OptimizationDirection::Minimize) {
result.at(state) = *std::min_element(choice_it, choice_it + rowGroupSize);
choice_it += rowGroupSize;
optChoice_it = std::min_element(choiceValue_it, choiceValue_it + rowGroupSize);
} else { } else {
result.at(state) = *std::max_element(choice_it, choice_it + rowGroupSize);
choice_it += rowGroupSize;
optChoice_it = std::max_element(choiceValue_it, choiceValue_it + rowGroupSize);
} }
} }
result.at(state) = *optChoice_it;
if(choices) {
choices->at(state) = std::distance(choiceValue_it, optChoice_it);
}
choiceValue_it += rowGroupSize;
} }
} }

2
src/storm/solver/Multiplier.h

@ -141,7 +141,7 @@ namespace storm {
*/ */
virtual void multiplyRow2(uint64_t const& rowIndex, std::vector<ValueType> const& x1, ValueType& val1, std::vector<ValueType> const& x2, ValueType& val2) const; virtual void multiplyRow2(uint64_t const& rowIndex, std::vector<ValueType> const& x1, ValueType& val1, std::vector<ValueType> const& x2, ValueType& val2) const;
void reduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType> const& choiceValues, std::vector<storm::storage::SparseMatrix<double>::index_type> rowGroupIndices, std::vector<ValueType>& result, storm::storage::BitVector const* dirOverride = nullptr) const;
void reduce(Environment const& env, OptimizationDirection const& dir, std::vector<storm::storage::SparseMatrix<double>::index_type> const& rowGroupIndices, std::vector<ValueType> const& choiceValues, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices = nullptr, storm::storage::BitVector const* dirOverride = nullptr) const;
protected: protected:
mutable std::unique_ptr<std::vector<ValueType>> cachedVector; mutable std::unique_ptr<std::vector<ValueType>> cachedVector;

74
src/storm/storage/PostScheduler.cpp

@ -9,14 +9,10 @@ namespace storm {
namespace storage { namespace storage {
template <typename ValueType> template <typename ValueType>
PostScheduler<ValueType>::PostScheduler(uint_fast64_t numberOfModelStates, std::vector<uint_fast64_t> numberOfChoicesPerState, boost::optional<storm::storage::MemoryStructure> const& memoryStructure) : Scheduler<ValueType>(numberOfModelStates, memoryStructure) {
STORM_LOG_DEBUG(numberOfChoicesPerState.size() << " " << numberOfModelStates);
STORM_LOG_ASSERT(numberOfChoicesPerState.size() == numberOfModelStates, "Need to know amount of choices per model state");
PostScheduler<ValueType>::PostScheduler(uint_fast64_t numberOfModelStates, std::vector<uint_fast64_t> numberOfChoicesPerState, boost::optional<storm::storage::MemoryStructure> const& memoryStructure) : memoryStructure(memoryStructure) {
//STORM_LOG_ASSERT(numberOfChoicesPerState.size() == numberOfModelStates, "Need to know amount of choices per model state");
uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1; uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
schedulerChoiceMapping = std::vector<std::vector<std::vector<SchedulerChoice<ValueType>>>>(numOfMemoryStates, std::vector<std::vector<SchedulerChoice<ValueType>>>(numberOfModelStates));
for(uint state = 0; state < numberOfModelStates; state++) {
schedulerChoiceMapping[0][state].resize(numberOfChoicesPerState[state]);
}
schedulerChoiceMapping = std::vector<std::vector<PostSchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<PostSchedulerChoice<ValueType>>(numberOfModelStates));
numberOfChoices = 0; numberOfChoices = 0;
for(std::vector<uint_fast64_t>::iterator it = numberOfChoicesPerState.begin(); it != numberOfChoicesPerState.end(); ++it) for(std::vector<uint_fast64_t>::iterator it = numberOfChoicesPerState.begin(); it != numberOfChoicesPerState.end(); ++it)
numberOfChoices += *it; numberOfChoices += *it;
@ -25,13 +21,10 @@ namespace storm {
} }
template <typename ValueType> template <typename ValueType>
PostScheduler<ValueType>::PostScheduler(uint_fast64_t numberOfModelStates, std::vector<uint_fast64_t> numberOfChoicesPerState, boost::optional<storm::storage::MemoryStructure>&& memoryStructure) : Scheduler<ValueType>(numberOfModelStates, std::move(memoryStructure)) {
PostScheduler<ValueType>::PostScheduler(uint_fast64_t numberOfModelStates, std::vector<uint_fast64_t> numberOfChoicesPerState, boost::optional<storm::storage::MemoryStructure>&& memoryStructure) : memoryStructure(std::move(memoryStructure)) {
STORM_LOG_ASSERT(numberOfChoicesPerState.size() == numberOfModelStates, "Need to know amount of choices per model state"); STORM_LOG_ASSERT(numberOfChoicesPerState.size() == numberOfModelStates, "Need to know amount of choices per model state");
uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1; uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
schedulerChoiceMapping = std::vector<std::vector<std::vector<SchedulerChoice<ValueType>>>>(numOfMemoryStates, std::vector<std::vector<SchedulerChoice<ValueType>>>(numberOfModelStates));
for(uint state = 0; state < numberOfModelStates; state++) {
schedulerChoiceMapping[0][state].resize(numberOfChoicesPerState[state]);
}
schedulerChoiceMapping = std::vector<std::vector<PostSchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<PostSchedulerChoice<ValueType>>(numberOfModelStates));
numberOfChoices = 0; numberOfChoices = 0;
for(std::vector<uint_fast64_t>::iterator it = numberOfChoicesPerState.begin(); it != numberOfChoicesPerState.end(); ++it) for(std::vector<uint_fast64_t>::iterator it = numberOfChoicesPerState.begin(); it != numberOfChoicesPerState.end(); ++it)
numberOfChoices += *it; numberOfChoices += *it;
@ -40,21 +33,13 @@ namespace storm {
} }
template <typename ValueType> template <typename ValueType>
void PostScheduler<ValueType>::setChoice(OldChoice const& oldChoice, SchedulerChoice<ValueType> const& newChoice, uint_fast64_t modelState, uint_fast64_t memoryState) {
void PostScheduler<ValueType>::setChoice(PostSchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState) {
STORM_LOG_ASSERT(memoryState == 0, "Currently we do not support PostScheduler with memory"); STORM_LOG_ASSERT(memoryState == 0, "Currently we do not support PostScheduler with memory");
STORM_LOG_ASSERT(modelState < schedulerChoiceMapping[memoryState].size(), "Illegal model state index"); STORM_LOG_ASSERT(modelState < schedulerChoiceMapping[memoryState].size(), "Illegal model state index");
schedulerChoiceMapping[memoryState][modelState][oldChoice] = newChoice;
}
template <typename ValueType>
SchedulerChoice<ValueType> const& PostScheduler<ValueType>::getChoice(uint_fast64_t modelState, OldChoice oldChoice, uint_fast64_t memoryState) {
STORM_LOG_ASSERT(memoryState < this->getNumberOfMemoryStates(), "Illegal memory state index");
STORM_LOG_ASSERT(modelState < schedulerChoiceMapping[memoryState].size(), "Illegal model state index");
return schedulerChoiceMapping[memoryState][modelState][oldChoice];
schedulerChoiceMapping[memoryState][modelState] = choice;
} }
template <typename ValueType> template <typename ValueType>
bool PostScheduler<ValueType>::isDeterministicScheduler() const { bool PostScheduler<ValueType>::isDeterministicScheduler() const {
return true; return true;
@ -89,7 +74,11 @@ namespace storm {
out << ":" << std::endl; out << ":" << std::endl;
uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0; uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
for (uint_fast64_t state = 0; state < schedulerChoiceMapping.front().size(); ++state) { for (uint_fast64_t state = 0; state < schedulerChoiceMapping.front().size(); ++state) {
PostSchedulerChoice<ValueType> const& choices = schedulerChoiceMapping[0][state];
if(choices.isEmpty() && !printUndefinedChoices) continue;
std::stringstream stateString; std::stringstream stateString;
// Print the state info // Print the state info
if (stateValuationsGiven) { if (stateValuationsGiven) {
stateString << std::setw(widthOfStates) << (std::to_string(state) + ": " + model->getStateValuations().getStateInfo(state)); stateString << std::setw(widthOfStates) << (std::to_string(state) + ": " + model->getStateValuations().getStateInfo(state));
@ -98,42 +87,37 @@ namespace storm {
} }
stateString << " "; stateString << " ";
bool firstChoiceIndex = true; bool firstChoiceIndex = true;
for(uint choiceIndex = 0; choiceIndex < schedulerChoiceMapping[0][state].size(); choiceIndex++) {
SchedulerChoice<ValueType> const& choice = schedulerChoiceMapping[0][state][choiceIndex];
for(auto const& choiceMap : choices.getChoiceMap()) {
if(firstChoiceIndex) { if(firstChoiceIndex) {
firstChoiceIndex = false; firstChoiceIndex = false;
} else { } else {
stateString << "; "; stateString << "; ";
} }
if (choice.isDefined()) {
auto choiceProbPair = *(choice.getChoiceAsDistribution().begin());
if(choiceLabelsGiven) {
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceIndex);
stateString << std::to_string(choiceIndex) << " {" << boost::join(choiceLabels, ", ") << "}: ";
} else {
stateString << std::to_string(choiceIndex) << ": ";
}
//stateString << choiceProbPair.second << ": (";
if (choiceOriginsGiven) {
stateString << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
} else {
stateString << choiceProbPair.first;
}
if (choiceLabelsGiven) {
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
stateString << " {" << boost::join(choiceLabels, ", ") << "}";
}
if(choiceLabelsGiven) {
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + std::get<0>(choiceMap));
stateString << std::to_string(std::get<0>(choiceMap)) << " {" << boost::join(choiceLabels, ", ") << "}: ";
} else {
stateString << std::to_string(std::get<0>(choiceMap)) << ": ";
}
if (choiceOriginsGiven) {
stateString << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + std::get<1>(choiceMap));
} else { } else {
if(!this->printUndefinedChoices) goto skipStatesWithUndefinedChoices;
stateString << "undefined.";
stateString << std::to_string(std::get<1>(choiceMap));
} }
if (choiceLabelsGiven) {
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + std::get<1>(choiceMap));
stateString << " {" << boost::join(choiceLabels, ", ") << "}";
}
// Todo: print memory updates // Todo: print memory updates
} }
out << stateString.str() << std::endl; out << stateString.str() << std::endl;
// jump to label if we find one undefined choice. // jump to label if we find one undefined choice.
skipStatesWithUndefinedChoices:;
//skipStatesWithUndefinedChoices:;
} }
out << "___________________________________________________________________" << std::endl; out << "___________________________________________________________________" << std::endl;
} }

22
src/storm/storage/PostScheduler.h

@ -2,7 +2,7 @@
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include "storm/storage/SchedulerChoice.h"
#include "storm/storage/PostSchedulerChoice.h"
#include "storm/storage/Scheduler.h" #include "storm/storage/Scheduler.h"
#include "storm/logic/ShieldExpression.h" #include "storm/logic/ShieldExpression.h"
@ -16,7 +16,7 @@ namespace storm {
* A Choice can be undefined, deterministic * A Choice can be undefined, deterministic
*/ */
template <typename ValueType> template <typename ValueType>
class PostScheduler : public Scheduler<ValueType> {
class PostScheduler {
public: public:
typedef uint_fast64_t OldChoice; typedef uint_fast64_t OldChoice;
/*! /*!
@ -35,7 +35,7 @@ namespace storm {
* @param modelState The state of the model for which to set the choice. * @param modelState The state of the model for which to set the choice.
* @param memoryState The state of the memoryStructure for which to set the choice. * @param memoryState The state of the memoryStructure for which to set the choice.
*/ */
void setChoice(OldChoice const& oldChoice, SchedulerChoice<ValueType> const& newChoice, uint_fast64_t modelState, uint_fast64_t memoryState = 0);
void setChoice(PostSchedulerChoice<ValueType> const& newChoice, uint_fast64_t modelState, uint_fast64_t memoryState = 0);
/*! /*!
* Is the scheduler defined on the states indicated by the selected-states bitvector? * Is the scheduler defined on the states indicated by the selected-states bitvector?
@ -50,14 +50,6 @@ namespace storm {
*/ */
void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0); void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0);
/*!
* Gets the choice defined by the scheduler for the given model and memory state.
*
* @param state The state for which to get the choice.
* @param memoryState the memory state which we consider.
*/
SchedulerChoice<ValueType> const& getChoice(uint_fast64_t modelState, OldChoice oldChoice, uint_fast64_t memoryState = 0) ;
/*! /*!
* Compute the Action Support: A bit vector that indicates all actions that are selected with positive probability in some memory state * Compute the Action Support: A bit vector that indicates all actions that are selected with positive probability in some memory state
*/ */
@ -92,8 +84,14 @@ namespace storm {
*/ */
void printToStream(std::ostream& out, std::shared_ptr<storm::logic::ShieldExpression const> shieldingExpression, std::shared_ptr<storm::models::sparse::Model<ValueType>> model = nullptr, bool skipUniqueChoices = false) const; void printToStream(std::ostream& out, std::shared_ptr<storm::logic::ShieldExpression const> shieldingExpression, std::shared_ptr<storm::models::sparse::Model<ValueType>> model = nullptr, bool skipUniqueChoices = false) const;
private: private:
std::vector<std::vector<std::vector<SchedulerChoice<ValueType>>>> schedulerChoiceMapping;
boost::optional<storm::storage::MemoryStructure> memoryStructure;
std::vector<std::vector<PostSchedulerChoice<ValueType>>> schedulerChoiceMapping;
bool printUndefinedChoices = false;
uint_fast64_t numOfUndefinedChoices;
uint_fast64_t numOfDeterministicChoices;
uint_fast64_t numOfDontCareStates;
std::vector<uint_fast64_t> numberOfChoicesPerState; std::vector<uint_fast64_t> numberOfChoicesPerState;
uint_fast64_t numberOfChoices; uint_fast64_t numberOfChoices;
}; };

63
src/storm/storage/PostSchedulerChoice.cpp

@ -0,0 +1,63 @@
#include "storm/storage/PostSchedulerChoice.h"
#include "storm/utility/constants.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/adapters/RationalNumberAdapter.h"
namespace storm {
namespace storage {
template <typename ValueType>
PostSchedulerChoice<ValueType>::PostSchedulerChoice() {
// Intentionally left empty
}
template <typename ValueType>
void PostSchedulerChoice<ValueType>::addChoice(uint_fast64_t oldChoiceIndex, uint_fast64_t newChoiceIndex) {
choiceMap.emplace_back(oldChoiceIndex, newChoiceIndex);
}
template <typename ValueType>
std::vector<std::tuple<uint_fast64_t, uint_fast64_t>> const& PostSchedulerChoice<ValueType>::getChoiceMap() const {
return choiceMap;
}
template <typename ValueType>
std::tuple<uint_fast64_t, uint_fast64_t> const& PostSchedulerChoice<ValueType>::getChoice(uint_fast64_t choiceIndex) const {
return choiceMap.at(choiceIndex);
}
template <typename ValueType>
bool PostSchedulerChoice<ValueType>::isEmpty() const {
return choiceMap.size() == 0;
}
template <typename ValueType>
std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<ValueType> const& schedulerChoice) {
if (!schedulerChoice.isEmpty()) {
bool firstChoice = true;
for(auto const& choice : schedulerChoice.getChoiceMap()) {
if(firstChoice) firstChoice = false;
else out << ", ";
out << std::get<0>(choice) << " -> " << std::get<1>(choice);
}
} else {
out << "undefined";
}
return out;
}
template class PostSchedulerChoice<double>;
template std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<double> const& schedulerChoice);
template class PostSchedulerChoice<float>;
template std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<float> const& schedulerChoice);
template class PostSchedulerChoice<storm::RationalNumber>;
template std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<storm::RationalNumber> const& schedulerChoice);
template class PostSchedulerChoice<storm::RationalFunction>;
template std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<storm::RationalFunction> const& schedulerChoice);
}
}

46
src/storm/storage/PostSchedulerChoice.h

@ -0,0 +1,46 @@
#pragma once
#include "storm/utility/constants.h"
namespace storm {
namespace storage {
template <typename ValueType>
class PostSchedulerChoice {
public:
/*!
* Creates an undefined scheduler choice
*/
PostSchedulerChoice();
/*
*
*/
void addChoice(uint_fast64_t oldChoiceIndex, uint_fast64_t newChoiceIndex);
/*
*
*/
bool isEmpty() const;
/*
*
*/
std::vector<std::tuple<uint_fast64_t, uint_fast64_t>> const& getChoiceMap() const;
/*
*
*/
std::tuple<uint_fast64_t, uint_fast64_t> const& getChoice(uint_fast64_t choiceIndex) const;
private:
//std::vector<std::tuple<uint_fast64_t, storm::storage::Distribution<ValueType, uint_fast64_t>>> choiceMap;
std::vector<std::tuple<uint_fast64_t, uint_fast64_t>> choiceMap;
};
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, PostSchedulerChoice<ValueType> const& schedulerChoice);
}
}

43
src/storm/storage/PreScheduler.cpp

@ -8,11 +8,36 @@
namespace storm { namespace storm {
namespace storage { namespace storage {
template <typename ValueType> template <typename ValueType>
PreScheduler<ValueType>::PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure) : Scheduler<ValueType>(numberOfModelStates, memoryStructure) {
PreScheduler<ValueType>::PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure) : memoryStructure(memoryStructure) {
uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
schedulerChoices = std::vector<std::vector<PreSchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<PreSchedulerChoice<ValueType>>(numberOfModelStates));
//dontCareStates = std::vector<storm::storage::BitVector>(numOfMemoryStates, storm::storage::BitVector(numberOfModelStates, false));
numOfUndefinedChoices = numOfMemoryStates * numberOfModelStates;
numOfDeterministicChoices = 0;
numOfDontCareStates = 0;
} }
template <typename ValueType> template <typename ValueType>
PreScheduler<ValueType>::PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure) : Scheduler<ValueType>(numberOfModelStates, std::move(memoryStructure)) {
PreScheduler<ValueType>::PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure) : memoryStructure(std::move(memoryStructure)) {
}
template <typename ValueType>
bool PreScheduler<ValueType>::isMemorylessScheduler() const {
return getNumberOfMemoryStates() == 1;
}
template <typename ValueType>
uint_fast64_t PreScheduler<ValueType>::getNumberOfMemoryStates() const {
return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
}
template <typename ValueType>
void PreScheduler<ValueType>::setChoice(PreSchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState) {
STORM_LOG_ASSERT(memoryState < this->getNumberOfMemoryStates(), "Illegal memory state index");
STORM_LOG_ASSERT(modelState < this->schedulerChoices[memoryState].size(), "Illegal model state index");
auto& schedulerChoice = schedulerChoices[memoryState][modelState];
schedulerChoice = choice;
} }
template <typename ValueType> template <typename ValueType>
@ -67,23 +92,23 @@ namespace storm {
} }
// Print choice info // Print choice info
SchedulerChoice<ValueType> const& choice = this->schedulerChoices[memoryState][state];
if (choice.isDefined()) {
PreSchedulerChoice<ValueType> const& choices = this->schedulerChoices[memoryState][state];
if (!choices.isEmpty()) {
bool firstChoice = true; bool firstChoice = true;
for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
for (auto const& choiceProbPair : choices.getChoiceMap()) {
if (firstChoice) { if (firstChoice) {
firstChoice = false; firstChoice = false;
} else { } else {
stateString << "; "; stateString << "; ";
} }
stateString << choiceProbPair.second << ": (";
stateString << std::get<0>(choiceProbPair) << ": (";
if (choiceOriginsGiven) { if (choiceOriginsGiven) {
stateString << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
stateString << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + std::get<1>(choiceProbPair));
} else { } else {
stateString << choiceProbPair.first;
stateString << std::get<1>(choiceProbPair);
} }
if (choiceLabelsGiven) { if (choiceLabelsGiven) {
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] + std::get<1>(choiceProbPair));
stateString << " {" << boost::join(choiceLabels, ", ") << "}"; stateString << " {" << boost::join(choiceLabels, ", ") << "}";
} }
stateString << ")"; stateString << ")";

28
src/storm/storage/PreScheduler.h

@ -3,7 +3,7 @@
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include <memory> #include <memory>
#include "storm/storage/SchedulerChoice.h"
#include "storm/storage/PreSchedulerChoice.h"
#include "storm/storage/Scheduler.h" #include "storm/storage/Scheduler.h"
#include "storm/logic/ShieldExpression.h" #include "storm/logic/ShieldExpression.h"
@ -12,14 +12,11 @@ namespace storm {
/* /*
* TODO needs obvious changes in all comment blocks * TODO needs obvious changes in all comment blocks
* This class defines which action is chosen in a particular state of a non-deterministic model. More concretely, a scheduler maps a state s to i
* if the scheduler takes the i-th action available in s (i.e. the choices are relative to the states).
* A Choice can be undefined, deterministic
*/ */
template <typename ValueType> template <typename ValueType>
class PreScheduler : public Scheduler<ValueType> {
class PreScheduler {
public: public:
typedef uint_fast64_t OldChoice;
/*! /*!
* Initializes a scheduler for the given number of model states. * Initializes a scheduler for the given number of model states.
* *
@ -29,14 +26,25 @@ namespace storm {
PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure = boost::none); PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure = boost::none);
PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure); PreScheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure);
bool isMemorylessScheduler() const;
uint_fast64_t getNumberOfMemoryStates() const;
void setChoice(PreSchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState);
/*! /*!
* Prints the scheduler to the given output stream. * Prints the scheduler to the given output stream.
* @param out The output stream
* @param model If given, provides additional information for printing (e.g., displaying the state valuations instead of state indices)
* @param skipUniqueChoices If true, the (unique) choice for deterministic states (i.e., states with only one enabled choice) is not printed explicitly.
* Requires a model to be given.
*/ */
void printToStream(std::ostream& out, std::shared_ptr<storm::logic::ShieldExpression const> shieldingExpression, std::shared_ptr<storm::models::sparse::Model<ValueType>> model = nullptr, bool skipUniqueChoices = false) const; void printToStream(std::ostream& out, std::shared_ptr<storm::logic::ShieldExpression const> shieldingExpression, std::shared_ptr<storm::models::sparse::Model<ValueType>> model = nullptr, bool skipUniqueChoices = false) const;
private:
boost::optional<storm::storage::MemoryStructure> memoryStructure;
std::vector<std::vector<PreSchedulerChoice<ValueType>>> schedulerChoices;
bool printUndefinedChoices = false;
uint_fast64_t numOfUndefinedChoices;
uint_fast64_t numOfDeterministicChoices;
uint_fast64_t numOfDontCareStates;
}; };
} }
} }

56
src/storm/storage/PreSchedulerChoice.cpp

@ -0,0 +1,56 @@
#include "storm/storage/PreSchedulerChoice.h"
#include "storm/utility/constants.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/adapters/RationalNumberAdapter.h"
namespace storm {
namespace storage {
template <typename ValueType>
PreSchedulerChoice<ValueType>::PreSchedulerChoice() {
// Intentionally left empty
}
template <typename ValueType>
void PreSchedulerChoice<ValueType>::addChoice(uint_fast64_t choiceIndex, ValueType probToSatisfy) {
choiceMap.emplace_back(probToSatisfy, choiceIndex);
}
template <typename ValueType>
std::vector<std::tuple<ValueType, uint_fast64_t>> const& PreSchedulerChoice<ValueType>::getChoiceMap() const {
return choiceMap;
}
template <typename ValueType>
bool PreSchedulerChoice<ValueType>::isEmpty() const {
return choiceMap.size() == 0;
}
template <typename ValueType>
std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<ValueType> const& schedulerChoice) {
out << schedulerChoice.getChoiceMap().size();
if (!schedulerChoice.isEmpty()) {
for(auto const& choice : schedulerChoice.getChoiceMap()) {
out << std::get<0>(choice) << ": " << std::get<1>(choice);
}
} else {
out << "undefined";
}
return out;
}
template class PreSchedulerChoice<double>;
template std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<double> const& schedulerChoice);
template class PreSchedulerChoice<float>;
template std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<float> const& schedulerChoice);
template class PreSchedulerChoice<storm::RationalNumber>;
template std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<storm::RationalNumber> const& schedulerChoice);
template class PreSchedulerChoice<storm::RationalFunction>;
template std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<storm::RationalFunction> const& schedulerChoice);
}
}

42
src/storm/storage/PreSchedulerChoice.h

@ -0,0 +1,42 @@
#pragma once
#include "storm/utility/constants.h"
namespace storm {
namespace storage {
template <typename ValueType>
class PreSchedulerChoice {
public:
/*!
* Creates an undefined scheduler choice
*/
PreSchedulerChoice();
/*
*
*/
void addChoice(uint_fast64_t choiceIndex, ValueType probToSatisfy);
/*
*
*/
bool isEmpty() const;
/*
*
*/
std::vector<std::tuple<ValueType, uint_fast64_t>> const& getChoiceMap() const;
private:
// For now we only consider shields with deterministic choices.
//std::map<ValueType, storm::storage::Distribution<ValueType, uint_fast64_t>> choiceMap;
std::vector<std::tuple<ValueType, uint_fast64_t>> choiceMap;
};
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, PreSchedulerChoice<ValueType> const& schedulerChoice);
}
}

16
src/test/storm/modelchecker/rpatl/smg/ShieldGenerationSmgRpatlModelCheckerTest.cpp

@ -108,22 +108,22 @@ namespace {
// testing create shielding expressions // testing create shielding expressions
std::string formulasString = "<" + fileNames[0] + ", PreSafety, lambda=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]"; std::string formulasString = "<" + fileNames[0] + ", PreSafety, lambda=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[1] + ", PreSafety, lambda=0.9> <<hiker>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[1] + ", PreSafety, lambda=0.9> <<native>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[2] + ", PreSafety, gamma=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]"; formulasString += "; <" + fileNames[2] + ", PreSafety, gamma=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[3] + ", PreSafety, gamma=0.9> <<hiker>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[3] + ", PreSafety, gamma=0.9> <<native>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[4] + ", PostSafety, lambda=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]"; formulasString += "; <" + fileNames[4] + ", PostSafety, lambda=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[5] + ", PostSafety, lambda=0.9> <<hiker>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[5] + ", PostSafety, lambda=0.9> <<native>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[6] + ", PostSafety, gamma=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]"; formulasString += "; <" + fileNames[6] + ", PostSafety, gamma=0.9> <<hiker>> Pmax=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[7] + ", PostSafety, gamma=0.9> <<hiker>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[7] + ", PostSafety, gamma=0.9> <<native>> Pmin=? [ F <=3 \"target\" ]";
formulasString += "; <" + fileNames[8] + ", PreSafety, lambda=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]"; formulasString += "; <" + fileNames[8] + ", PreSafety, lambda=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[9] + ", PreSafety, lambda=0.5> <<hiker>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[9] + ", PreSafety, lambda=0.5> <<native>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[10] + ", PreSafety, gamma=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]"; formulasString += "; <" + fileNames[10] + ", PreSafety, gamma=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[11] + ", PreSafety, gamma=0.5> <<hiker>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[11] + ", PreSafety, gamma=0.5> <<native>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[12] + ", PostSafety, lambda=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]"; formulasString += "; <" + fileNames[12] + ", PostSafety, lambda=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[13] + ", PostSafety, lambda=0.5> <<hiker>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[13] + ", PostSafety, lambda=0.5> <<native>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[14] + ", PostSafety, gamma=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]"; formulasString += "; <" + fileNames[14] + ", PostSafety, gamma=0.5> <<hiker>> Pmax=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[15] + ", PostSafety, gamma=0.5> <<hiker>> Pmin=? [ F <=5 \"target\" ]";
formulasString += "; <" + fileNames[15] + ", PostSafety, gamma=0.5> <<native>> Pmin=? [ F <=5 \"target\" ]";
auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/smg/rightDecision.nm", formulasString); auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/smg/rightDecision.nm", formulasString);
auto smg = std::move(modelFormulas.first); auto smg = std::move(modelFormulas.first);

5
src/test/storm/parser/GameShieldingParserTest.cpp

@ -28,7 +28,7 @@ TEST(GameShieldingParserTest, PreSafetyShieldTest) {
EXPECT_EQ(filename, shieldExpression->getFilename()); EXPECT_EQ(filename, shieldExpression->getFilename());
} }
TEST(GameShieldingParserTest, PostSafetyShieldTest) {
TEST(GameShieldingParserTest, PostShieldTest) {
storm::parser::FormulaParser formulaParser; storm::parser::FormulaParser formulaParser;
std::string filename = "postSafetyShieldFileName"; std::string filename = "postSafetyShieldFileName";
@ -76,6 +76,5 @@ TEST(GameShieldingParserTest, OptimalShieldTest) {
EXPECT_FALSE(shieldExpression->isPreSafetyShield()); EXPECT_FALSE(shieldExpression->isPreSafetyShield());
EXPECT_FALSE(shieldExpression->isPostSafetyShield()); EXPECT_FALSE(shieldExpression->isPostSafetyShield());
EXPECT_TRUE(shieldExpression->isOptimalShield()); EXPECT_TRUE(shieldExpression->isOptimalShield());
EXPECT_FALSE(shieldExpression->isRelative());
EXPECT_EQ(filename, shieldExpression->getFilename()); EXPECT_EQ(filename, shieldExpression->getFilename());
}
}

5
src/test/storm/parser/MdpShieldingParserTest.cpp

@ -25,7 +25,7 @@ TEST(MdpShieldingParserTest, PreSafetyShieldTest) {
EXPECT_EQ(filename, shieldExpression->getFilename()); EXPECT_EQ(filename, shieldExpression->getFilename());
} }
TEST(MdpShieldingParserTest, PostSafetyShieldTest) {
TEST(MdpShieldingParserTest, PostShieldTest) {
storm::parser::FormulaParser formulaParser; storm::parser::FormulaParser formulaParser;
std::string filename = "postSafetyShieldFileName"; std::string filename = "postSafetyShieldFileName";
@ -67,6 +67,5 @@ TEST(MdpShieldingParserTest, OptimalShieldTest) {
EXPECT_FALSE(shieldExpression->isPreSafetyShield()); EXPECT_FALSE(shieldExpression->isPreSafetyShield());
EXPECT_FALSE(shieldExpression->isPostSafetyShield()); EXPECT_FALSE(shieldExpression->isPostSafetyShield());
EXPECT_TRUE(shieldExpression->isOptimalShield()); EXPECT_TRUE(shieldExpression->isOptimalShield());
EXPECT_FALSE(shieldExpression->isRelative());
EXPECT_EQ(filename, shieldExpression->getFilename()); EXPECT_EQ(filename, shieldExpression->getFilename());
}
}
Loading…
Cancel
Save