From e0a71f331c8e0acdaebc9f91a297048a8fc214a5 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 13 Aug 2020 11:42:46 +0200 Subject: [PATCH 01/50] do not clear moduleToIndexMap for second run --- src/storm-parsers/parser/PrismParser.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm-parsers/parser/PrismParser.h b/src/storm-parsers/parser/PrismParser.h index 2668dcb68..d7105acc4 100644 --- a/src/storm-parsers/parser/PrismParser.h +++ b/src/storm-parsers/parser/PrismParser.h @@ -37,7 +37,6 @@ namespace storm { formulas.clear(); globalBooleanVariables.clear(); globalIntegerVariables.clear(); - moduleToIndexMap.clear(); modules.clear(); rewardModels.clear(); labels.clear(); From 584fbf23c1d69b9ed6c23a96743c157b98075e78 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 13 Aug 2020 18:49:53 +0200 Subject: [PATCH 02/50] add assertion for module indices in second --- src/storm-parsers/parser/PrismParser.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/storm-parsers/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp index 0368d843c..a9bd43547 100644 --- a/src/storm-parsers/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -755,12 +755,16 @@ namespace storm { this->observables.insert(observables.begin(), observables.end()); // We need this list to be filled in both runs. } - + storm::prism::Module PrismParser::createModule(std::string const& moduleName, std::vector const& booleanVariables, std::vector const& integerVariables, std::vector const& clockVariables, boost::optional const& invariant, std::vector const& commands, GlobalProgramInformation& globalProgramInformation) const { - globalProgramInformation.moduleToIndexMap[moduleName] = globalProgramInformation.modules.size(); + if (!this->secondRun) { + globalProgramInformation.moduleToIndexMap[moduleName] = globalProgramInformation.modules.size(); + } else { + STORM_LOG_THROW(globalProgramInformation.moduleToIndexMap[moduleName] == globalProgramInformation.modules.size(), storm::exceptions::WrongFormatException, "Internal error while parsing: the index for module " << moduleName << " does not match the on in the first run."); + } return storm::prism::Module(moduleName, booleanVariables, integerVariables, clockVariables, invariant.is_initialized()? invariant.get() : storm::expressions::Expression(), commands, this->getFilename()); } - + bool PrismParser::isValidModuleRenaming(std::string const& oldModuleName, storm::prism::ModuleRenaming const& moduleRenaming, GlobalProgramInformation const& globalProgramInformation) const { if (!this->secondRun) { auto const& renaming = moduleRenaming.getRenaming(); From eba20bb0059424782ae20940d2309ca786d3021d Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 14:24:48 +0100 Subject: [PATCH 03/50] switch cases in engine now feature SMG case --- src/storm/utility/Engine.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/storm/utility/Engine.cpp b/src/storm/utility/Engine.cpp index 8eaecde4e..d431f5343 100644 --- a/src/storm/utility/Engine.cpp +++ b/src/storm/utility/Engine.cpp @@ -123,6 +123,7 @@ namespace storm { case ModelType::MA: return storm::modelchecker::SparseMarkovAutomatonCslModelChecker>::canHandleStatic(checkTask); case ModelType::POMDP: + case ModelType::SMG: return false; } break; @@ -137,6 +138,7 @@ namespace storm { case ModelType::MA: return storm::modelchecker::HybridMarkovAutomatonCslModelChecker>::canHandleStatic(checkTask); case ModelType::POMDP: + case ModelType::SMG: return false; } break; @@ -149,6 +151,7 @@ namespace storm { case ModelType::CTMC: case ModelType::MA: case ModelType::POMDP: + case ModelType::SMG: return false; } break; @@ -177,6 +180,7 @@ namespace storm { case ModelType::MDP: case ModelType::MA: case ModelType::POMDP: + case ModelType::SMG: return false; } break; @@ -189,6 +193,7 @@ namespace storm { case ModelType::MDP: case ModelType::MA: case ModelType::POMDP: + case ModelType::SMG: return false; } break; @@ -200,6 +205,7 @@ namespace storm { case ModelType::CTMC: case ModelType::MA: case ModelType::POMDP: + case ModelType::SMG: return false; } break; From 2225ebcbe8d3e1aba9bf26870e56a37cf0f04e0b Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 14:25:35 +0100 Subject: [PATCH 04/50] fix reorder warning --- src/storm/storage/prism/Program.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/storm/storage/prism/Program.h b/src/storm/storage/prism/Program.h index 095f164ff..56610556f 100644 --- a/src/storm/storage/prism/Program.h +++ b/src/storm/storage/prism/Program.h @@ -757,18 +757,18 @@ namespace storm { // A mapping of formula names to their corresponding indices. std::map formulaToIndexMap; - // The modules associated with the program. - std::vector modules; - - // A mapping of module names to their indices. - std::map moduleToIndexMap; - // The players associated with the program. std::vector players; // A mapping of player names to their indices. std::map playerToIndexMap; + // The modules associated with the program. + std::vector modules; + + // A mapping of module names to their indices. + std::map moduleToIndexMap; + // The reward models associated with the program. std::vector rewardModels; From cbbafaddfd1bf6fdd9a0a4c66c5e0e4d54415ebb Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:13:20 +0100 Subject: [PATCH 05/50] added Coalition class will be used in rPATL formulas --- src/storm/logic/Coalition.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/storm/logic/Coalition.cpp diff --git a/src/storm/logic/Coalition.cpp b/src/storm/logic/Coalition.cpp new file mode 100644 index 000000000..ff67d735b --- /dev/null +++ b/src/storm/logic/Coalition.cpp @@ -0,0 +1,23 @@ +#include "storm/logic/Coalition.h" + +namespace storm { + namespace logic { + + Coalition::Coalition(std::vector const& playerNames, + std::vector const& playerIds) : playerNames(playerNames), playerIds(playerIds) { + // Intentionally left empty. + } + + std::ostream& operator<<(std::ostream& stream, Coalition const& coalition) { + stream << "<<"; + for (auto const& playerName : coalition.playerNames) { + stream << playerName << ", "; + } + for (auto const& playerId : coalition.playerIds) { + stream << playerId << ", "; + } + stream << ">>"; + return stream; + } + } +} From 6dd9e09edefa8e8f9bf7bc9d00d4a1871bc1d605 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:12:54 +0100 Subject: [PATCH 06/50] added GameFormula class --- src/storm/logic/GameFormula.cpp | 34 ++++++++++++++++++++++++++++++++ src/storm/logic/GameFormula.h | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/storm/logic/GameFormula.cpp create mode 100644 src/storm/logic/GameFormula.h diff --git a/src/storm/logic/GameFormula.cpp b/src/storm/logic/GameFormula.cpp new file mode 100644 index 000000000..8e42f7e65 --- /dev/null +++ b/src/storm/logic/GameFormula.cpp @@ -0,0 +1,34 @@ +#include "storm/logic/GameFormula.h" + +#include "storm/logic/FormulaVisitor.h" + +namespace storm { + namespace logic { + GameFormula::GameFormula(Coalition coalition, std::shared_ptr subFormula) : coalition(coalition), subformula(subformula) { + STORM_PRINT_AND_LOG("CTOR subf usecount:" << subformula.use_count() << std::endl); + // Intentionally left empty. + } + + bool GameFormula::isGameFormula() const { + return true; + } + + Formula const& GameFormula::getSubformula() const { + return *subformula; + } + + Coalition GameFormula::getCoalition() const { + return coalition; + } + + boost::any GameFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { + return visitor.visit(*this, data); + } + + std::ostream& GameFormula::writeToStream(std::ostream& out) const { + out << coalition; + this->getSubformula().writeToStream(out); + return out; + } + } +} diff --git a/src/storm/logic/GameFormula.h b/src/storm/logic/GameFormula.h new file mode 100644 index 000000000..81384ddcf --- /dev/null +++ b/src/storm/logic/GameFormula.h @@ -0,0 +1,35 @@ +#ifndef STORM_LOGIC_GAMEFORMULA_H_ +#define STORM_LOGIC_GAMEFORMULA_H_ + +#include "storm/logic/Formula.h" +#include "storm/logic/Coalition.h" +#include + +namespace storm { + namespace logic { + class GameFormula : public Formula { + public: + GameFormula(Coalition coalition, std::shared_ptr subFormula); + + ~GameFormula() { + // Intentionally left empty. + } + + bool isGameFormula() const; + + Formula const& getSubformula() const; + Coalition getCoalition() const; + + boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const; + + std::ostream& writeToStream(std::ostream& out) const; + + private: + Coalition coalition; + std::shared_ptr subformula; + + }; + } +} + +#endif /* STORM_LOGIC_GAMEFORMULA_H_ */ From c52fcba6a27eb4a8effc092c9c955920971dbe5f Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:08:51 +0100 Subject: [PATCH 07/50] added multiple Visitor methods for gameFormulas --- src/storm/logic/CloneVisitor.cpp | 18 +- src/storm/logic/CloneVisitor.h | 1 + src/storm/logic/Formula.cpp | 246 +++++++++--------- src/storm/logic/Formula.h | 7 +- src/storm/logic/FormulaInformationVisitor.cpp | 18 +- src/storm/logic/FormulaInformationVisitor.h | 1 + src/storm/logic/FormulaVisitor.h | 1 + src/storm/logic/Formulas.h | 1 + src/storm/logic/FormulasForwardDeclarations.h | 1 + src/storm/logic/FragmentChecker.cpp | 10 +- src/storm/logic/FragmentChecker.h | 1 + .../LiftableTransitionRewardsVisitor.cpp | 18 +- .../logic/LiftableTransitionRewardsVisitor.h | 1 + src/storm/logic/ToExpressionVisitor.cpp | 36 +-- src/storm/logic/ToExpressionVisitor.h | 1 + src/storm/storage/jani/JSONExporter.cpp | 10 +- src/storm/storage/jani/JSONExporter.h | 1 + 17 files changed, 208 insertions(+), 164 deletions(-) diff --git a/src/storm/logic/CloneVisitor.cpp b/src/storm/logic/CloneVisitor.cpp index cb24e7d8b..8c8d82ca2 100644 --- a/src/storm/logic/CloneVisitor.cpp +++ b/src/storm/logic/CloneVisitor.cpp @@ -76,30 +76,36 @@ namespace storm { return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); } } - + boost::any CloneVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); return std::static_pointer_cast(std::make_shared(subformula, f.getOperatorInformation())); } - + boost::any CloneVisitor::visit(GloballyFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); return std::static_pointer_cast(std::make_shared(subformula)); } - + + boost::any CloneVisitor::visit(GameFormula const& f, boost::any const& data) const { + STORM_PRINT_AND_LOG("CloneVisitor called for GameFormula\n"); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(f.getCoalition(), subformula)); + } + boost::any CloneVisitor::visit(InstantaneousRewardFormula const& f, boost::any const&) const { return std::static_pointer_cast(std::make_shared(f)); } - + boost::any CloneVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); return std::static_pointer_cast(std::make_shared(subformula, f.getOperatorInformation())); } - + boost::any CloneVisitor::visit(LongRunAverageRewardFormula const& f, boost::any const&) const { return std::static_pointer_cast(std::make_shared(f)); } - + boost::any CloneVisitor::visit(MultiObjectiveFormula const& f, boost::any const& data) const { std::vector> subformulas; for(auto const& subF : f.getSubformulas()){ diff --git a/src/storm/logic/CloneVisitor.h b/src/storm/logic/CloneVisitor.h index 4b1d620ee..5ff29e816 100644 --- a/src/storm/logic/CloneVisitor.h +++ b/src/storm/logic/CloneVisitor.h @@ -22,6 +22,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const override; diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 58970c77b..0a310713d 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -14,313 +14,317 @@ namespace storm { bool Formula::isPathFormula() const { return false; } - + bool Formula::isStateFormula() const { return false; } - + bool Formula::isMultiObjectiveFormula() const { return false; } - + bool Formula::isQuantileFormula() const { return false; } - + bool Formula::isBinaryStateFormula() const { return false; } - + bool Formula::isUnaryStateFormula() const { return false; } - + bool Formula::isBinaryBooleanStateFormula() const { return false; } - + bool Formula::isUnaryBooleanStateFormula() const { return false; } - + bool Formula::isBooleanLiteralFormula() const { return false; } - + bool Formula::isTrueFormula() const { return false; } - + bool Formula::isFalseFormula() const { return false; } - + bool Formula::isAtomicExpressionFormula() const { return false; } - + bool Formula::isAtomicLabelFormula() const { return false; } - + bool Formula::isUntilFormula() const { return false; } - + bool Formula::isBoundedUntilFormula() const { return false; } - + bool Formula::isEventuallyFormula() const { return false; } - + bool Formula::isReachabilityProbabilityFormula() const { return false; } - + bool Formula::isGloballyFormula() const { return false; } - + bool Formula::isBinaryPathFormula() const { return false; } - + bool Formula::isUnaryPathFormula() const { return false; } - + bool Formula::isConditionalProbabilityFormula() const { return false; } - + bool Formula::isConditionalRewardFormula() const { return false; } - + bool Formula::isProbabilityPathFormula() const { return false; } - + bool Formula::isRewardPathFormula() const { return false; } - + bool Formula::isTimePathFormula() const { return false; } - + bool Formula::isNextFormula() const { return false; } - + bool Formula::isLongRunAverageOperatorFormula() const { return false; } - + bool Formula::isTimeOperatorFormula() const { return false; } - + bool Formula::isCumulativeRewardFormula() const { return false; } - + bool Formula::isInstantaneousRewardFormula() const { return false; } - + bool Formula::isReachabilityRewardFormula() const { return false; } - + bool Formula::isLongRunAverageRewardFormula() const { return false; } - + bool Formula::isTotalRewardFormula() const { return false; } - + bool Formula::isReachabilityTimeFormula() const { return false; } - + + bool Formula::isGameFormula() const { + return false; + } + bool Formula::isProbabilityOperatorFormula() const { return false; } - + bool Formula::isRewardOperatorFormula() const { return false; } - + bool Formula::isOperatorFormula() const { return false; } - + bool Formula::hasQualitativeResult() const { return true; } - + bool Formula::hasQuantitativeResult() const { return false; } - + bool Formula::isInFragment(FragmentSpecification const& fragment) const { FragmentChecker checker; return checker.conformsToSpecification(*this, fragment); } - + FormulaInformation Formula::info() const { FormulaInformationVisitor visitor; return visitor.getInformation(*this); } - + std::shared_ptr Formula::getTrueFormula() { return std::shared_ptr(new BooleanLiteralFormula(true)); } - + bool Formula::isInitialFormula() const { return this->isAtomicLabelFormula() && this->asAtomicLabelFormula().getLabel() == "init"; } - + PathFormula& Formula::asPathFormula() { return dynamic_cast(*this); } - + PathFormula const& Formula::asPathFormula() const { return dynamic_cast(*this); } - + StateFormula& Formula::asStateFormula() { return dynamic_cast(*this); } - + StateFormula const& Formula::asStateFormula() const { return dynamic_cast(*this); } - + MultiObjectiveFormula& Formula::asMultiObjectiveFormula() { return dynamic_cast(*this); } - + MultiObjectiveFormula const& Formula::asMultiObjectiveFormula() const { return dynamic_cast(*this); } - + QuantileFormula& Formula::asQuantileFormula() { return dynamic_cast(*this); } - + QuantileFormula const& Formula::asQuantileFormula() const { return dynamic_cast(*this); } - + BinaryStateFormula& Formula::asBinaryStateFormula() { return dynamic_cast(*this); } - + BinaryStateFormula const& Formula::asBinaryStateFormula() const { return dynamic_cast(*this); } - + UnaryStateFormula& Formula::asUnaryStateFormula() { return dynamic_cast(*this); } - + UnaryStateFormula const& Formula::asUnaryStateFormula() const { return dynamic_cast(*this); } - + ConditionalFormula& Formula::asConditionalFormula() { return dynamic_cast(*this); } - + ConditionalFormula const& Formula::asConditionalFormula() const { return dynamic_cast(*this); } - + BinaryBooleanStateFormula& Formula::asBinaryBooleanStateFormula() { return dynamic_cast(*this); } - + BinaryBooleanStateFormula const& Formula::asBinaryBooleanStateFormula() const { return dynamic_cast(*this); } - + UnaryBooleanStateFormula& Formula::asUnaryBooleanStateFormula() { return dynamic_cast(*this); } - + UnaryBooleanStateFormula const& Formula::asUnaryBooleanStateFormula() const { return dynamic_cast(*this); } - + BooleanLiteralFormula& Formula::asBooleanLiteralFormula() { return dynamic_cast(*this); } - + BooleanLiteralFormula const& Formula::asBooleanLiteralFormula() const { return dynamic_cast(*this); } - + AtomicExpressionFormula& Formula::asAtomicExpressionFormula() { return dynamic_cast(*this); } - + AtomicExpressionFormula const& Formula::asAtomicExpressionFormula() const { return dynamic_cast(*this); } - + AtomicLabelFormula& Formula::asAtomicLabelFormula() { return dynamic_cast(*this); } - + AtomicLabelFormula const& Formula::asAtomicLabelFormula() const { return dynamic_cast(*this); } - + UntilFormula& Formula::asUntilFormula() { return dynamic_cast(*this); } - + UntilFormula const& Formula::asUntilFormula() const { return dynamic_cast(*this); } - + BoundedUntilFormula& Formula::asBoundedUntilFormula() { return dynamic_cast(*this); } - + BoundedUntilFormula const& Formula::asBoundedUntilFormula() const { return dynamic_cast(*this); } - + EventuallyFormula& Formula::asEventuallyFormula() { return dynamic_cast(*this); } - + EventuallyFormula const& Formula::asEventuallyFormula() const { return dynamic_cast(*this); } - + EventuallyFormula& Formula::asReachabilityRewardFormula() { return dynamic_cast(*this); } - + EventuallyFormula const& Formula::asReachabilityRewardFormula() const { return dynamic_cast(*this); } - + EventuallyFormula& Formula::asReachabilityProbabilityFormula() { return dynamic_cast(*this); } - + EventuallyFormula const& Formula::asReachabilityProbabilityFormula() const { return dynamic_cast(*this); } - + EventuallyFormula& Formula::asReachabilityTimeFormula() { return dynamic_cast(*this); } @@ -328,160 +332,160 @@ namespace storm { EventuallyFormula const& Formula::asReachabilityTimeFormula() const { return dynamic_cast(*this); } - + GloballyFormula& Formula::asGloballyFormula() { return dynamic_cast(*this); } - + GloballyFormula const& Formula::asGloballyFormula() const { return dynamic_cast(*this); } - + BinaryPathFormula& Formula::asBinaryPathFormula() { return dynamic_cast(*this); } - + BinaryPathFormula const& Formula::asBinaryPathFormula() const { return dynamic_cast(*this); } - + UnaryPathFormula& Formula::asUnaryPathFormula() { return dynamic_cast(*this); } - + UnaryPathFormula const& Formula::asUnaryPathFormula() const { return dynamic_cast(*this); } - + NextFormula& Formula::asNextFormula() { return dynamic_cast(*this); } - + NextFormula const& Formula::asNextFormula() const { return dynamic_cast(*this); } - + LongRunAverageOperatorFormula& Formula::asLongRunAverageOperatorFormula() { return dynamic_cast(*this); } - + LongRunAverageOperatorFormula const& Formula::asLongRunAverageOperatorFormula() const { return dynamic_cast(*this); } - + TimeOperatorFormula& Formula::asTimeOperatorFormula() { return dynamic_cast(*this); } - + TimeOperatorFormula const& Formula::asTimeOperatorFormula() const { return dynamic_cast(*this); } - + CumulativeRewardFormula& Formula::asCumulativeRewardFormula() { return dynamic_cast(*this); } - + CumulativeRewardFormula const& Formula::asCumulativeRewardFormula() const { return dynamic_cast(*this); } - + TotalRewardFormula& Formula::asTotalRewardFormula() { return dynamic_cast(*this); } - + TotalRewardFormula const& Formula::asTotalRewardFormula() const { return dynamic_cast(*this); } - + InstantaneousRewardFormula& Formula::asInstantaneousRewardFormula() { return dynamic_cast(*this); } - + InstantaneousRewardFormula const& Formula::asInstantaneousRewardFormula() const { return dynamic_cast(*this); } - + LongRunAverageRewardFormula& Formula::asLongRunAverageRewardFormula() { return dynamic_cast(*this); } - + LongRunAverageRewardFormula const& Formula::asLongRunAverageRewardFormula() const { return dynamic_cast(*this); } - + ProbabilityOperatorFormula& Formula::asProbabilityOperatorFormula() { return dynamic_cast(*this); } - + ProbabilityOperatorFormula const& Formula::asProbabilityOperatorFormula() const { return dynamic_cast(*this); } - + RewardOperatorFormula& Formula::asRewardOperatorFormula() { return dynamic_cast(*this); } - + RewardOperatorFormula const& Formula::asRewardOperatorFormula() const { return dynamic_cast(*this); } - + OperatorFormula& Formula::asOperatorFormula() { return dynamic_cast(*this); } - + OperatorFormula const& Formula::asOperatorFormula() const { return dynamic_cast(*this); } - + std::vector> Formula::getAtomicExpressionFormulas() const { std::vector> result; this->gatherAtomicExpressionFormulas(result); return result; } - + std::vector> Formula::getAtomicLabelFormulas() const { std::vector> result; this->gatherAtomicLabelFormulas(result); return result; } - + std::set Formula::getUsedVariables() const { std::set usedVariables; this->gatherUsedVariables(usedVariables); return usedVariables; } - + std::set Formula::getReferencedRewardModels() const { std::set referencedRewardModels; this->gatherReferencedRewardModels(referencedRewardModels); return referencedRewardModels; } - + std::shared_ptr Formula::substitute(std::map const& substitution) const { storm::expressions::JaniExpressionSubstitutionVisitor> v(substitution); return substitute([&v](storm::expressions::Expression const& exp) {return v.substitute(exp);}); } - + std::shared_ptr Formula::substitute(std::function const& expressionSubstitution) const { ExpressionSubstitutionVisitor visitor; return visitor.substitute(*this, expressionSubstitution); } - + std::shared_ptr Formula::substitute(std::map const& labelSubstitution) const { LabelSubstitutionVisitor visitor(labelSubstitution); return visitor.substitute(*this); } - + std::shared_ptr Formula::substitute(std::map const& labelSubstitution) const { LabelSubstitutionVisitor visitor(labelSubstitution); return visitor.substitute(*this); } - + std::shared_ptr Formula::substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const { RewardModelNameSubstitutionVisitor visitor(rewardModelNameSubstitution); return visitor.substitute(*this); } - + storm::expressions::Expression Formula::toExpression(storm::expressions::ExpressionManager const& manager, std::map const& labelToExpressionMapping) const { ToExpressionVisitor visitor; if (labelToExpressionMapping.empty()) { @@ -490,37 +494,37 @@ namespace storm { return visitor.toExpression(*this->substitute(labelToExpressionMapping), manager); } } - + std::shared_ptr Formula::asSharedPointer() { return this->shared_from_this(); } - + std::shared_ptr Formula::asSharedPointer() const { return this->shared_from_this(); } - + void Formula::gatherAtomicExpressionFormulas(std::vector>&) const { return; } - + void Formula::gatherAtomicLabelFormulas(std::vector>&) const { return; } - + void Formula::gatherReferencedRewardModels(std::set&) const { return; } - + void Formula::gatherUsedVariables(std::set& usedVariables) const { return; } - + std::string Formula::toString() const { std::stringstream str2; writeToStream(str2); return str2.str(); } - + std::ostream& operator<<(std::ostream& out, Formula const& formula) { return formula.writeToStream(out); } diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index dc6396e71..8fabb4fe0 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -78,10 +78,13 @@ namespace storm { virtual bool isReachabilityRewardFormula() const; virtual bool isLongRunAverageRewardFormula() const; virtual bool isTotalRewardFormula() const; - + // Expected time formulas. virtual bool isReachabilityTimeFormula() const; - + + // Game formulas. + virtual bool isGameFormula() const; + // Type checks for abstract intermediate classes. virtual bool isBinaryPathFormula() const; virtual bool isBinaryStateFormula() const; diff --git a/src/storm/logic/FormulaInformationVisitor.cpp b/src/storm/logic/FormulaInformationVisitor.cpp index e4e9a15ed..41976aa57 100644 --- a/src/storm/logic/FormulaInformationVisitor.cpp +++ b/src/storm/logic/FormulaInformationVisitor.cpp @@ -60,36 +60,40 @@ namespace storm { } return result; } - + boost::any FormulaInformationVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + boost::any FormulaInformationVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + boost::any FormulaInformationVisitor::visit(GloballyFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + + boost::any FormulaInformationVisitor::visit(GameFormula const& f, boost::any const& data) const { + return f.getSubformula().accept(*this, data); + } + boost::any FormulaInformationVisitor::visit(InstantaneousRewardFormula const&, boost::any const&) const { return FormulaInformation(); } - + boost::any FormulaInformationVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { FormulaInformation result; result.setContainsLongRunFormula(true); result.join(boost::any_cast(f.getSubformula().accept(*this, data))); return result; } - + boost::any FormulaInformationVisitor::visit(LongRunAverageRewardFormula const&, boost::any const&) const { FormulaInformation result; result.setContainsLongRunFormula(true); return result; } - + boost::any FormulaInformationVisitor::visit(MultiObjectiveFormula const& f, boost::any const& data) const { FormulaInformation result; for(auto const& subF : f.getSubformulas()){ diff --git a/src/storm/logic/FormulaInformationVisitor.h b/src/storm/logic/FormulaInformationVisitor.h index 7ba8b70b9..617386961 100644 --- a/src/storm/logic/FormulaInformationVisitor.h +++ b/src/storm/logic/FormulaInformationVisitor.h @@ -21,6 +21,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const override; diff --git a/src/storm/logic/FormulaVisitor.h b/src/storm/logic/FormulaVisitor.h index 1eaf6791d..6bf5b8c50 100644 --- a/src/storm/logic/FormulaVisitor.h +++ b/src/storm/logic/FormulaVisitor.h @@ -22,6 +22,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const = 0; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const = 0; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const = 0; diff --git a/src/storm/logic/Formulas.h b/src/storm/logic/Formulas.h index bdda5c863..f054794e7 100644 --- a/src/storm/logic/Formulas.h +++ b/src/storm/logic/Formulas.h @@ -8,6 +8,7 @@ #include "storm/logic/BoundedUntilFormula.h" #include "storm/logic/CumulativeRewardFormula.h" #include "storm/logic/EventuallyFormula.h" +#include "storm/logic/GameFormula.h" #include "storm/logic/GloballyFormula.h" #include "storm/logic/InstantaneousRewardFormula.h" #include "storm/logic/NextFormula.h" diff --git a/src/storm/logic/FormulasForwardDeclarations.h b/src/storm/logic/FormulasForwardDeclarations.h index 170316fc7..2d1661418 100644 --- a/src/storm/logic/FormulasForwardDeclarations.h +++ b/src/storm/logic/FormulasForwardDeclarations.h @@ -17,6 +17,7 @@ namespace storm { class EventuallyFormula; class TimeOperatorFormula; class GloballyFormula; + class GameFormula; class InstantaneousRewardFormula; class LongRunAverageOperatorFormula; class LongRunAverageRewardFormula; diff --git a/src/storm/logic/FragmentChecker.cpp b/src/storm/logic/FragmentChecker.cpp index b669e75bd..fb95572f9 100644 --- a/src/storm/logic/FragmentChecker.cpp +++ b/src/storm/logic/FragmentChecker.cpp @@ -188,12 +188,18 @@ namespace storm { result && boost::any_cast(f.getSubformula().accept(*this, data)); return result; } - + + boost::any FragmentChecker::visit(GameFormula const& f, boost::any const& data) const { + InheritedInformation const& inherited = boost::any_cast(data); + bool result = inherited.getSpecification().areCoalitionOperatorsAllowed(); + return result && boost::any_cast(f.getSubformula().accept(*this, data)); + } + boost::any FragmentChecker::visit(InstantaneousRewardFormula const&, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast(data); return inherited.getSpecification().areInstantaneousRewardFormulasAllowed(); } - + boost::any FragmentChecker::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast(data); bool result = inherited.getSpecification().areLongRunAverageOperatorsAllowed(); diff --git a/src/storm/logic/FragmentChecker.h b/src/storm/logic/FragmentChecker.h index 485a205aa..c6e6100ee 100644 --- a/src/storm/logic/FragmentChecker.h +++ b/src/storm/logic/FragmentChecker.h @@ -22,6 +22,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const override; diff --git a/src/storm/logic/LiftableTransitionRewardsVisitor.cpp b/src/storm/logic/LiftableTransitionRewardsVisitor.cpp index 99eeb444b..bdb8ba58e 100644 --- a/src/storm/logic/LiftableTransitionRewardsVisitor.cpp +++ b/src/storm/logic/LiftableTransitionRewardsVisitor.cpp @@ -62,31 +62,35 @@ namespace storm { } return true; } - + boost::any LiftableTransitionRewardsVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + boost::any LiftableTransitionRewardsVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + boost::any LiftableTransitionRewardsVisitor::visit(GloballyFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + + boost::any LiftableTransitionRewardsVisitor::visit(GameFormula const& f, boost::any const& data) const { + return true; + } + boost::any LiftableTransitionRewardsVisitor::visit(InstantaneousRewardFormula const&, boost::any const&) const { return true; } - + boost::any LiftableTransitionRewardsVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { return f.getSubformula().accept(*this, data); } - + boost::any LiftableTransitionRewardsVisitor::visit(LongRunAverageRewardFormula const&, boost::any const&) const { return true; } - + boost::any LiftableTransitionRewardsVisitor::visit(MultiObjectiveFormula const& f, boost::any const& data) const { bool result = true; for (auto const& subF : f.getSubformulas()){ diff --git a/src/storm/logic/LiftableTransitionRewardsVisitor.h b/src/storm/logic/LiftableTransitionRewardsVisitor.h index c09f9c25b..bbac6b7c2 100644 --- a/src/storm/logic/LiftableTransitionRewardsVisitor.h +++ b/src/storm/logic/LiftableTransitionRewardsVisitor.h @@ -28,6 +28,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const override; diff --git a/src/storm/logic/ToExpressionVisitor.cpp b/src/storm/logic/ToExpressionVisitor.cpp index 27ea1fa6b..8eb8444fc 100644 --- a/src/storm/logic/ToExpressionVisitor.cpp +++ b/src/storm/logic/ToExpressionVisitor.cpp @@ -46,67 +46,71 @@ namespace storm { } return result; } - + boost::any ToExpressionVisitor::visit(BoundedUntilFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(ConditionalFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(CumulativeRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(EventuallyFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(TimeOperatorFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(GloballyFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + + boost::any ToExpressionVisitor::visit(GameFormula const&, boost::any const&) const { + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); + } + boost::any ToExpressionVisitor::visit(InstantaneousRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(LongRunAverageOperatorFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(LongRunAverageRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(MultiObjectiveFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(QuantileFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(NextFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(ProbabilityOperatorFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(RewardOperatorFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(TotalRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot assemble expression from formula that contains illegal elements."); } - + boost::any ToExpressionVisitor::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const { storm::expressions::Expression subexpression = boost::any_cast(f.getSubformula().accept(*this, data)); switch (f.getOperator()) { diff --git a/src/storm/logic/ToExpressionVisitor.h b/src/storm/logic/ToExpressionVisitor.h index 345698f5a..675dbbcba 100644 --- a/src/storm/logic/ToExpressionVisitor.h +++ b/src/storm/logic/ToExpressionVisitor.h @@ -22,6 +22,7 @@ namespace storm { virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(GloballyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(GameFormula const& f, boost::any const& data) const override; virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageRewardFormula const& f, boost::any const& data) const override; diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 79748e5da..4236f4c6f 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -324,18 +324,22 @@ namespace storm { } return opDecl; } - + boost::any FormulaToJaniJson::visit(storm::logic::GloballyFormula const& f, boost::any const& data) const { ExportJsonType opDecl; opDecl["op"] = "G"; opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); return opDecl; } - + + boost::any FormulaToJaniJson::visit(storm::logic::GameFormula const& f, boost::any const& data) const { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We currently do not support conversion of game formulas to Jani. (Does jani support games?)"); + } + boost::any FormulaToJaniJson::visit(storm::logic::InstantaneousRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of an instanteneous reward formula"); } - + boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const { ExportJsonType opDecl; if(f.hasBound()) { diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 7c11358c6..9408cff82 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -57,6 +57,7 @@ namespace storm { virtual boost::any visit(storm::logic::CumulativeRewardFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const; + virtual boost::any visit(storm::logic::GameFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::GloballyFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::InstantaneousRewardFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const; From 8dc46968cbe7edbd3f8ef144affef8064a832318 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:11:20 +0100 Subject: [PATCH 08/50] added rPATL to FragmentSpecifitcations --- src/storm/logic/FragmentSpecification.cpp | 34 ++++++++++--- src/storm/logic/FragmentSpecification.h | 60 +++++++++++++---------- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index 9405a3841..898b9f626 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -41,21 +41,30 @@ namespace storm { pctl.setBoundedUntilFormulasAllowed(true); pctl.setStepBoundedUntilFormulasAllowed(true); pctl.setTimeBoundedUntilFormulasAllowed(true); - + return pctl; } - + FragmentSpecification flatPctl() { FragmentSpecification flatPctl = pctl(); - + flatPctl.setNestedOperatorsAllowed(false); - + return flatPctl; } - + + FragmentSpecification rpatl() { + FragmentSpecification rpatl = pctl(); + + // TODO disallow operator we currently do not support + rpatl.setCoalitionOperatorsAllowed(true); + + return rpatl; + } + FragmentSpecification prctl() { FragmentSpecification prctl = pctl(); - + prctl.setRewardOperatorsAllowed(true); prctl.setCumulativeRewardFormulasAllowed(true); prctl.setInstantaneousFormulasAllowed(true); @@ -614,12 +623,21 @@ namespace storm { bool FragmentSpecification::isRewardAccumulationAllowed() const { return rewardAccumulation; } - + FragmentSpecification& FragmentSpecification::setRewardAccumulationAllowed(bool newValue) { rewardAccumulation = newValue; return *this; } - + bool FragmentSpecification::areCoalitionOperatorsAllowed() const { + return coalitionOperator; + } + + FragmentSpecification& FragmentSpecification::setCoalitionOperatorsAllowed(bool newValue) { + coalitionOperator = newValue; + return *this; + } + + } } diff --git a/src/storm/logic/FragmentSpecification.h b/src/storm/logic/FragmentSpecification.h index aa48c0738..830c2a9a0 100644 --- a/src/storm/logic/FragmentSpecification.h +++ b/src/storm/logic/FragmentSpecification.h @@ -93,105 +93,110 @@ namespace storm { bool areNestedOperatorsAllowed() const; FragmentSpecification& setNestedOperatorsAllowed(bool newValue); - + bool areNestedPathFormulasAllowed() const; FragmentSpecification& setNestedPathFormulasAllowed(bool newValue); - + bool areNestedMultiObjectiveFormulasAllowed() const; FragmentSpecification& setNestedMultiObjectiveFormulasAllowed(bool newValue); - + bool areNestedOperatorsInsideMultiObjectiveFormulasAllowed() const; FragmentSpecification& setNestedOperatorsInsideMultiObjectiveFormulasAllowed(bool newValue); - + bool areOnlyEventuallyFormuluasInConditionalFormulasAllowed() const; FragmentSpecification& setOnlyEventuallyFormuluasInConditionalFormulasAllowed(bool newValue); bool areStepBoundedUntilFormulasAllowed() const; FragmentSpecification& setStepBoundedUntilFormulasAllowed(bool newValue); - + bool areTimeBoundedUntilFormulasAllowed() const; FragmentSpecification& setTimeBoundedUntilFormulasAllowed(bool newValue); bool areRewardBoundedUntilFormulasAllowed() const; FragmentSpecification& setRewardBoundedUntilFormulasAllowed(bool newValue); - + bool areMultiDimensionalBoundedUntilFormulasAllowed() const; FragmentSpecification& setMultiDimensionalBoundedUntilFormulasAllowed(bool newValue); - + bool areStepBoundedCumulativeRewardFormulasAllowed() const; FragmentSpecification& setStepBoundedCumulativeRewardFormulasAllowed(bool newValue); - + bool areTimeBoundedCumulativeRewardFormulasAllowed() const; FragmentSpecification& setTimeBoundedCumulativeRewardFormulasAllowed(bool newValue); bool areRewardBoundedCumulativeRewardFormulasAllowed() const; FragmentSpecification& setRewardBoundedCumulativeRewardFormulasAllowed(bool newValue); - + bool areMultiDimensionalCumulativeRewardFormulasAllowed() const; FragmentSpecification& setMultiDimensionalCumulativeRewardFormulasAllowed(bool newValue); - + bool isVarianceMeasureTypeAllowed() const; FragmentSpecification& setVarianceMeasureTypeAllowed(bool newValue); - + bool areQuantitativeOperatorResultsAllowed() const; FragmentSpecification& setQuantitativeOperatorResultsAllowed(bool newValue); bool areQualitativeOperatorResultsAllowed() const; FragmentSpecification& setQualitativeOperatorResultsAllowed(bool newValue); - + bool isOperatorAtTopLevelRequired() const; FragmentSpecification& setOperatorAtTopLevelRequired(bool newValue); - + bool isMultiObjectiveFormulaAtTopLevelRequired() const; FragmentSpecification& setMultiObjectiveFormulaAtTopLevelRequired(bool newValue); - + bool areOperatorsAtTopLevelOfMultiObjectiveFormulasRequired() const; FragmentSpecification& setOperatorsAtTopLevelOfMultiObjectiveFormulasRequired(bool newValue); - + bool isQuantileFormulaAtTopLevelRequired() const; FragmentSpecification& setQuantileFormulaAtTopLevelRequired(bool newValue); - + bool isRewardAccumulationAllowed() const; FragmentSpecification& setRewardAccumulationAllowed(bool newValue); - + bool areCoalitionOperatorsAllowed() const; + FragmentSpecification& setCoalitionOperatorsAllowed(bool newValue); + + FragmentSpecification& setOperatorsAllowed(bool newValue); FragmentSpecification& setTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); - + private: // Flags that indicate whether it is legal to see such a formula. bool probabilityOperator; bool rewardOperator; bool expectedTimeOperator; bool longRunAverageOperator; - + bool multiObjectiveFormula; bool quantileFormula; - + bool globallyFormula; bool reachabilityProbabilityFormula; bool nextFormula; bool untilFormula; bool boundedUntilFormula; - + bool atomicExpressionFormula; bool atomicLabelFormula; bool booleanLiteralFormula; bool unaryBooleanStateFormula; bool binaryBooleanStateFormula; - + bool cumulativeRewardFormula; bool instantaneousRewardFormula; bool reachabilityRewardFormula; bool longRunAverageRewardFormula; bool totalRewardFormula; - + bool conditionalProbabilityFormula; bool conditionalRewardFormula; - + bool reachabilityTimeFormula; - + + bool coalitionOperator; + // Members that indicate certain restrictions. bool nestedOperators; bool nestedPathFormulas; @@ -228,7 +233,10 @@ namespace storm { // Flat PCTL. FragmentSpecification flatPctl(); - + + // rPATL for SMGs + FragmentSpecification rpatl(); + // PCTL + cumulative, instantaneous, reachability and long-run rewards. FragmentSpecification prctl(); From 715784a070691e19d22dfc25483a309370f8abae Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:26:42 +0100 Subject: [PATCH 09/50] added casting getter for gameFormula --- src/storm/logic/Formula.cpp | 8 ++++++++ src/storm/logic/Formula.h | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 0a310713d..d8b399e34 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -333,6 +333,14 @@ namespace storm { return dynamic_cast(*this); } + GameFormula& Formula::asGameFormula() { + return dynamic_cast(*this); + } + + GameFormula const& Formula::asGameFormula() const { + return dynamic_cast(*this); + } + GloballyFormula& Formula::asGloballyFormula() { return dynamic_cast(*this); } diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index 8fabb4fe0..294637c2e 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -154,7 +154,10 @@ namespace storm { EventuallyFormula& asReachabilityTimeFormula(); EventuallyFormula const& asReachabilityTimeFormula() const; - + + GameFormula& asGameFormula(); + GameFormula const& asGameFormula() const; + GloballyFormula& asGloballyFormula(); GloballyFormula const& asGloballyFormula() const; From f106b83328e46e9e64757e91c53bb4558d957df0 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 19 Nov 2020 18:23:32 +0100 Subject: [PATCH 10/50] WIP added grammar rules for gameFormula Does not compile at this stage! This commit will be squashed asap. --- .../parser/FormulaParserGrammar.cpp | 22 +++++++++++++++++-- .../parser/FormulaParserGrammar.h | 10 +++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/storm-parsers/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp index 139c3e226..f27aa6e00 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -133,8 +133,19 @@ namespace storm { quantileBoundVariable.name("quantile bound variable"); quantileFormula = (qi::lit("quantile") > qi::lit("(") >> *(quantileBoundVariable) >> stateFormula > qi::lit(")"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createQuantileFormula, phoenix::ref(*this), qi::_1, qi::_2)]; quantileFormula.name("Quantile formula"); - - stateFormula = (orStateFormula | multiFormula | quantileFormula); + + coalitionOperator = (qi::lit("<<") + > *( (identifier[phoenix::push_back(qi::_a, qi::_1)] + | qi::int_[phoenix::push_back(qi::_b, qi::_1)]) % ',' + ) + > qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a, qi::_b)]; + coalitionOperator.name("coalition operator"); + + // only LRA for now, need to adapt this (beware of cyclic gameFormula pass!) + gameFormula = (coalitionOperator > longRunAverageOperator)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), storm::logic::Coalition({}, {1}), qi::_1)]; + gameFormula.name("game formula"); + + stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula); stateFormula.name("state formula"); formulaName = qi::lit("\"") >> identifier >> qi::lit("\"") >> qi::lit(":"); @@ -472,5 +483,12 @@ namespace storm { } } + storm::logic::Coalition FormulaParserGrammar::createCoalition(std::vector const& playerIdentifier, std::vector const& playerIds) const { + return storm::logic::Coalition(playerIdentifier, playerIds); + } + + std::shared_ptr FormulaParserGrammar::createGameFormula(storm::logic::Coalition coalition, std::shared_ptr const& subformula) const { + return std::shared_ptr(new storm::logic::GameFormula(coalition, subformula)); + } } } diff --git a/src/storm-parsers/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h index b60ef27f0..904d8c852 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -160,7 +160,9 @@ namespace storm { qi::rule(), Skipper> rewardOperator; qi::rule(), Skipper> timeOperator; qi::rule(), Skipper> longRunAverageOperator; - + + qi::rule, std::vector>, Skipper> coalitionOperator; + qi::rule filterProperty; qi::rule(), Skipper> simpleFormula; qi::rule(), Skipper> stateFormula; @@ -199,10 +201,14 @@ namespace storm { qi::rule(), Skipper> multiFormula; qi::rule>, Skipper> quantileBoundVariable; qi::rule(), Skipper> quantileFormula; - + qi::rule(), Skipper> gameFormula; + // Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). boost::spirit::qi::real_parser> strict_double; + storm::logic::Coalition createCoalition(std::vector const& playerIdentifier, std::vector const& playerIds) const; + std::shared_ptr createGameFormula(storm::logic::Coalition coalition, std::shared_ptr const& subformula) const; + bool areConstantDefinitionsAllowed() const; void addConstant(std::string const& name, ConstantDataType type, boost::optional const& expression); void addProperty(std::vector& properties, boost::optional const& name, std::shared_ptr const& formula); From 73e49458181102de6af5150062f52e499e7b59e0 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 13:20:46 +0100 Subject: [PATCH 11/50] add STORM_DEVELOPER ALL_WARNINGS GCC case non exhaustive in this commit, i.e. additional flags might be applicable --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index edf9fa3e3..cca67f466 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -325,6 +325,11 @@ if (STORM_DEVELOPER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-float-equal") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedef") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-variable-declarations") + elseif (GCC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs") endif () else () set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") From 376e4756db0d331d0e3ce31764f250ffeca5a472 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 13:44:46 +0100 Subject: [PATCH 12/50] added Coalition default ctor --- src/storm/logic/Coalition.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/storm/logic/Coalition.h diff --git a/src/storm/logic/Coalition.h b/src/storm/logic/Coalition.h new file mode 100644 index 000000000..108ea53ef --- /dev/null +++ b/src/storm/logic/Coalition.h @@ -0,0 +1,30 @@ +#ifndef STORM_LOGIC_COALITION_H_ +#define STORM_LOGIC_COALITION_H_ + +#include +#include + +#include +#include "storm/storage/BoostTypes.h" +#include "storm/utility/OsDetection.h" + +namespace storm { + namespace logic { + + class Coalition { + public: + Coalition() = default; + Coalition(std::vector const& playerNames, std::vector const& playerIds); + Coalition(Coalition const& other) = default; + + friend std::ostream& operator<<(std::ostream& stream, Coalition const& coalition); + + private: + std::vector playerNames; + std::vector playerIds; + }; + } +} + + +#endif /* STORM_LOGIC_COALITION_H_ */ From 53ac9a3873b8701e637f9adbc4db889bfe51bf53 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 13:45:16 +0100 Subject: [PATCH 13/50] fixed typo in arg list of GameFormula --- src/storm/logic/GameFormula.cpp | 3 +-- src/storm/logic/GameFormula.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storm/logic/GameFormula.cpp b/src/storm/logic/GameFormula.cpp index 8e42f7e65..697a695a0 100644 --- a/src/storm/logic/GameFormula.cpp +++ b/src/storm/logic/GameFormula.cpp @@ -4,8 +4,7 @@ namespace storm { namespace logic { - GameFormula::GameFormula(Coalition coalition, std::shared_ptr subFormula) : coalition(coalition), subformula(subformula) { - STORM_PRINT_AND_LOG("CTOR subf usecount:" << subformula.use_count() << std::endl); + GameFormula::GameFormula(Coalition coalition, std::shared_ptr const& subformula) : coalition(coalition), subformula(subformula) { // Intentionally left empty. } diff --git a/src/storm/logic/GameFormula.h b/src/storm/logic/GameFormula.h index 81384ddcf..113b9e65f 100644 --- a/src/storm/logic/GameFormula.h +++ b/src/storm/logic/GameFormula.h @@ -9,7 +9,7 @@ namespace storm { namespace logic { class GameFormula : public Formula { public: - GameFormula(Coalition coalition, std::shared_ptr subFormula); + GameFormula(Coalition coalition, std::shared_ptr const& subFormula); ~GameFormula() { // Intentionally left empty. From 84bcfef24e93e8c4b2f90541173e62b95210063e Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 17:49:12 +0100 Subject: [PATCH 14/50] removed print from CloneVisitor --- src/storm/logic/CloneVisitor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm/logic/CloneVisitor.cpp b/src/storm/logic/CloneVisitor.cpp index 8c8d82ca2..1d751bb2e 100644 --- a/src/storm/logic/CloneVisitor.cpp +++ b/src/storm/logic/CloneVisitor.cpp @@ -88,7 +88,6 @@ namespace storm { } boost::any CloneVisitor::visit(GameFormula const& f, boost::any const& data) const { - STORM_PRINT_AND_LOG("CloneVisitor called for GameFormula\n"); std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); return std::static_pointer_cast(std::make_shared(f.getCoalition(), subformula)); } From a9868fd50137ec38ae1432565ba0aaed95fc1fce Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Mon, 23 Nov 2020 18:09:24 +0100 Subject: [PATCH 15/50] refactor Coalition to use boost variant --- src/storm-parsers/parser/FormulaParserGrammar.cpp | 8 ++++---- src/storm-parsers/parser/FormulaParserGrammar.h | 6 ++++-- src/storm/logic/Coalition.cpp | 14 ++++++-------- src/storm/logic/Coalition.h | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/storm-parsers/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp index f27aa6e00..4984cc929 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -136,9 +136,9 @@ namespace storm { coalitionOperator = (qi::lit("<<") > *( (identifier[phoenix::push_back(qi::_a, qi::_1)] - | qi::int_[phoenix::push_back(qi::_b, qi::_1)]) % ',' + | qi::int_[phoenix::push_back(qi::_a, qi::_1)]) % ',' ) - > qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a, qi::_b)]; + > qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a)]; coalitionOperator.name("coalition operator"); // only LRA for now, need to adapt this (beware of cyclic gameFormula pass!) @@ -483,8 +483,8 @@ namespace storm { } } - storm::logic::Coalition FormulaParserGrammar::createCoalition(std::vector const& playerIdentifier, std::vector const& playerIds) const { - return storm::logic::Coalition(playerIdentifier, playerIds); + storm::logic::Coalition FormulaParserGrammar::createCoalition(std::vector> const& playerIds) const { + return storm::logic::Coalition(playerIds); } std::shared_ptr FormulaParserGrammar::createGameFormula(storm::logic::Coalition coalition, std::shared_ptr const& subformula) const { diff --git a/src/storm-parsers/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h index 904d8c852..7693019d3 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -3,6 +3,8 @@ #include #include +#include + #include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/storage/jani/Property.h" @@ -161,7 +163,7 @@ namespace storm { qi::rule(), Skipper> timeOperator; qi::rule(), Skipper> longRunAverageOperator; - qi::rule, std::vector>, Skipper> coalitionOperator; + qi::rule>>, Skipper> coalitionOperator; qi::rule filterProperty; qi::rule(), Skipper> simpleFormula; @@ -206,7 +208,7 @@ namespace storm { // Parser that is used to recognize doubles only (as opposed to Spirit's double_ parser). boost::spirit::qi::real_parser> strict_double; - storm::logic::Coalition createCoalition(std::vector const& playerIdentifier, std::vector const& playerIds) const; + storm::logic::Coalition createCoalition(std::vector> const& playerIds) const; std::shared_ptr createGameFormula(storm::logic::Coalition coalition, std::shared_ptr const& subformula) const; bool areConstantDefinitionsAllowed() const; diff --git a/src/storm/logic/Coalition.cpp b/src/storm/logic/Coalition.cpp index ff67d735b..0781aaece 100644 --- a/src/storm/logic/Coalition.cpp +++ b/src/storm/logic/Coalition.cpp @@ -3,20 +3,18 @@ namespace storm { namespace logic { - Coalition::Coalition(std::vector const& playerNames, - std::vector const& playerIds) : playerNames(playerNames), playerIds(playerIds) { + Coalition::Coalition(std::vector> playerIds) : playerIds(playerIds) { // Intentionally left empty. } std::ostream& operator<<(std::ostream& stream, Coalition const& coalition) { + bool firstItem = true; stream << "<<"; - for (auto const& playerName : coalition.playerNames) { - stream << playerName << ", "; + for (auto const& id : coalition.playerIds) { + if(firstItem) { firstItem = false; } else { stream << ","; } + stream << id; } - for (auto const& playerId : coalition.playerIds) { - stream << playerId << ", "; - } - stream << ">>"; + stream << ">> "; return stream; } } diff --git a/src/storm/logic/Coalition.h b/src/storm/logic/Coalition.h index 108ea53ef..73ea92ac4 100644 --- a/src/storm/logic/Coalition.h +++ b/src/storm/logic/Coalition.h @@ -5,6 +5,7 @@ #include #include +#include #include "storm/storage/BoostTypes.h" #include "storm/utility/OsDetection.h" @@ -14,14 +15,13 @@ namespace storm { class Coalition { public: Coalition() = default; - Coalition(std::vector const& playerNames, std::vector const& playerIds); + Coalition(std::vector>); Coalition(Coalition const& other) = default; friend std::ostream& operator<<(std::ostream& stream, Coalition const& coalition); private: - std::vector playerNames; - std::vector playerIds; + std::vector> playerIds; }; } } From 6cea1969530d2a53f3a971bdceb6f9faa4302e63 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 24 Nov 2020 16:05:13 +0100 Subject: [PATCH 16/50] rpatl smg formulas now accept operatorFormulas --- src/storm-parsers/parser/FormulaParserGrammar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storm-parsers/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp index 4984cc929..b6dde5a95 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -141,8 +141,7 @@ namespace storm { > qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a)]; coalitionOperator.name("coalition operator"); - // only LRA for now, need to adapt this (beware of cyclic gameFormula pass!) - gameFormula = (coalitionOperator > longRunAverageOperator)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), storm::logic::Coalition({}, {1}), qi::_1)]; + gameFormula = (coalitionOperator > operatorFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), qi::_1, qi::_2)]; gameFormula.name("game formula"); stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula); From 1470d65586b28de659ad2a0309cee2668808c3c9 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 10:41:15 +0100 Subject: [PATCH 17/50] gameForumlas now gather referenced variables --- src/storm/logic/GameFormula.cpp | 4 ++++ src/storm/logic/GameFormula.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/storm/logic/GameFormula.cpp b/src/storm/logic/GameFormula.cpp index 697a695a0..bdd74440c 100644 --- a/src/storm/logic/GameFormula.cpp +++ b/src/storm/logic/GameFormula.cpp @@ -20,6 +20,10 @@ namespace storm { return coalition; } + void GameFormula::gatherReferencedRewardModels(std::set& referencedRewardModels) const { + this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); + } + boost::any GameFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } diff --git a/src/storm/logic/GameFormula.h b/src/storm/logic/GameFormula.h index 113b9e65f..719571767 100644 --- a/src/storm/logic/GameFormula.h +++ b/src/storm/logic/GameFormula.h @@ -20,6 +20,8 @@ namespace storm { Formula const& getSubformula() const; Coalition getCoalition() const; + virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const; + boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const; std::ostream& writeToStream(std::ostream& out) const; From 353b98ec88bcf781249649b529fbb7f77fa26918 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:04:55 +0100 Subject: [PATCH 18/50] rpatl extends prctl --- src/storm/logic/FragmentSpecification.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index 898b9f626..6aa73cd5b 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -54,7 +54,7 @@ namespace storm { } FragmentSpecification rpatl() { - FragmentSpecification rpatl = pctl(); + FragmentSpecification rpatl = prctl(); // TODO disallow operator we currently do not support rpatl.setCoalitionOperatorsAllowed(true); From d939ebe375a658a726b2c65cafc6f40598e9d817 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:19:45 +0100 Subject: [PATCH 19/50] smg model now stores the player action indices --- src/storm/models/sparse/Smg.cpp | 12 ++++++++---- src/storm/models/sparse/Smg.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/storm/models/sparse/Smg.cpp b/src/storm/models/sparse/Smg.cpp index e0419844c..e7c20c9fa 100644 --- a/src/storm/models/sparse/Smg.cpp +++ b/src/storm/models/sparse/Smg.cpp @@ -6,6 +6,7 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/sparse/Mdp.h" namespace storm { namespace models { @@ -29,14 +30,17 @@ namespace storm { Smg::Smg(storm::storage::sparse::ModelComponents const& components, ModelType type) : NondeterministicModel(type, components) { assert(type == storm::models::ModelType::Smg); - // Intentionally left empty } - template + template Smg::Smg(storm::storage::sparse::ModelComponents&& components, ModelType type) - : NondeterministicModel(type, std::move(components)) { + : NondeterministicModel(type, std::move(components)), playerActionIndices(components.playerActionIndices.get()) { assert(type == storm::models::ModelType::Smg); - // Intentionally left empty + } + + template + std::vector Smg::getPlayerActionIndices() const { + return playerActionIndices; } template class Smg; diff --git a/src/storm/models/sparse/Smg.h b/src/storm/models/sparse/Smg.h index 663817418..2bf7146c8 100644 --- a/src/storm/models/sparse/Smg.h +++ b/src/storm/models/sparse/Smg.h @@ -48,6 +48,11 @@ namespace storm { Smg(Smg&& other) = default; Smg& operator=(Smg&& other) = default; + + std::vector getPlayerActionIndices() const; + + private: + std::vector playerActionIndices; }; } // namespace sparse From a29950436115b7177e73522cac788c1721ac5530 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:25:05 +0100 Subject: [PATCH 20/50] added smg rpatl model checker --- .../rpatl/SparseSmgRpatlModelChecker.cpp | 121 ++++++++++++++++++ .../rpatl/SparseSmgRpatlModelChecker.h | 38 ++++++ 2 files changed, 159 insertions(+) create mode 100644 src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp create mode 100644 src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp new file mode 100644 index 000000000..f6161fac2 --- /dev/null +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -0,0 +1,121 @@ +#include "storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h" + +#include +#include + +#include "storm/utility/macros.h" +#include "storm/utility/FilteredRewardModel.h" + +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h" + +#include "storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h" +#include "storm/modelchecker/helper/utility/SetInformationFromCheckTask.h" + +#include "storm/logic/FragmentSpecification.h" + +#include "storm/models/sparse/StandardRewardModel.h" + +#include "storm/settings/modules/GeneralSettings.h" + +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidPropertyException.h" +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace modelchecker { + template + SparseSmgRpatlModelChecker::SparseSmgRpatlModelChecker(SparseSmgModelType const& model) : SparsePropositionalModelChecker(model) { + // Intentionally left empty. + } + + template + bool SparseSmgRpatlModelChecker::canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState) { + storm::logic::Formula const& formula = checkTask.getFormula(); + + if (formula.isInFragment(storm::logic::rpatl().setCoalitionOperatorsAllowed(true).setRewardOperatorsAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageOperatorsAllowed(true))) { + return true; + } else { + return false; + } + } + + template + bool SparseSmgRpatlModelChecker::canHandle(CheckTask const& checkTask) const { + bool requiresSingleInitialState = false; + if (canHandleStatic(checkTask, &requiresSingleInitialState)) { + return !requiresSingleInitialState || this->getModel().getInitialStates().getNumberOfSetBits() == 1; + } else { + return false; + } + } + + template + std::unique_ptr SparseSmgRpatlModelChecker::checkGameFormula(Environment const& env, CheckTask const& checkTask) { + STORM_LOG_DEBUG("checkGameFormula matrix: " << this->getModel().getTransitionMatrix().getDimensionsAsString()); + STORM_LOG_DEBUG("checkGameFormula playerindices:"); + STORM_LOG_DEBUG("checkGameFormula matrix: \n" << this->getModel().getTransitionMatrix()); + // TODO set min max row groups w.r.t. coalition + storm::logic::GameFormula const& gameFormula = checkTask.getFormula(); + storm::logic::Formula const& subFormula = gameFormula.getSubformula(); + STORM_LOG_DEBUG(gameFormula); + if (subFormula.isRewardOperatorFormula()) { + return this->checkRewardOperatorFormula(env, checkTask.substituteFormula(subFormula.asRewardOperatorFormula())); + } else if (subFormula.isLongRunAverageOperatorFormula()) { + return this->checkLongRunAverageOperatorFormula(env, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula())); + } + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "checkGameFormula NYI"); + } + + template + std::unique_ptr SparseSmgRpatlModelChecker::checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) { + storm::logic::RewardOperatorFormula const& formula = checkTask.getFormula(); + std::unique_ptr result = this->computeRewards(env, formula.getMeasureType(), checkTask.substituteFormula(formula.getSubformula())); + + return nullptr; + } + + template + std::unique_ptr AbstractModelChecker::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { + storm::logic::Formula const& rewardFormula = checkTask.getFormula(); + if (rewardFormula.isLongRunAverageRewardFormula()) { + return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' is invalid."); + } + + template + std::unique_ptr AbstractModelChecker::checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask) { + storm::logic::LongRunAverageOperatorFormula const& formula = checkTask.getFormula(); + //STORM_LOG_THROW(formula.getSubformula().isStateFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); + + std::unique_ptr result = this->computeLongRunAverageProbabilities(env, checkTask.substituteFormula(formula.getSubformula().asStateFormula())); + + return result; //TODO check bounds. + } + + template + std::unique_ptr SparseSmgRpatlModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "NYI"); + } + + template + std::unique_ptr SparseSmgRpatlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { + auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); + storm::modelchecker::helper::SparseNondeterministicGameInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getPlayerActionIndices()); + storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); + auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); + + //std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values)); + //return result; + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "NYI"); + } + + template class SparseSmgRpatlModelChecker>; +#ifdef STORM_HAVE_CARL + template class SparseSmgRpatlModelChecker>; + //template class SparseSmgRpatlModelChecker>; TODO are we going to need this? +#endif + } +} diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h new file mode 100644 index 000000000..91bb09206 --- /dev/null +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h @@ -0,0 +1,38 @@ +#ifndef STORM_MODELCHECKER_SPARSESMGRPATLMODELCHECKER_H_ +#define STORM_MODELCHECKER_SPARSESMGRPATLMODELCHECKER_H_ + +#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" +#include "storm/models/sparse/Smg.h" +#include "storm/utility/solver.h" +#include "storm/solver/LinearEquationSolver.h" +#include "storm/storage/StronglyConnectedComponent.h" + +namespace storm { + namespace modelchecker { + + template + class SparseSmgRpatlModelChecker : public SparsePropositionalModelChecker { + public: + typedef typename SparseSmgModelType::ValueType ValueType; + typedef typename SparseSmgModelType::RewardModelType RewardModelType; + + explicit SparseSmgRpatlModelChecker(SparseSmgModelType const& model); + + /*! + * Returns false, if this task can certainly not be handled by this model checker (independent of the concrete model). + * @param requiresSingleInitialState if not nullptr, this flag is set to true iff checking this formula requires a model with a single initial state + */ + static bool canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState = nullptr); + + // The implemented methods of the AbstractModelChecker interface. + virtual bool canHandle(CheckTask const& checkTask) const override; + virtual std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask) override; + virtual std::unique_ptr checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) override; + + virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; + virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + }; + } // namespace modelchecker +} // namespace storm + +#endif /* STORM_MODELCHECKER_SPARSESMGRPATLMODELCHECKER_H_ */ From e88a83d9aa9b0bc6135e8f95c885c96ab0807a00 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:27:48 +0100 Subject: [PATCH 21/50] engine now checks smg models --- src/storm/utility/Engine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storm/utility/Engine.cpp b/src/storm/utility/Engine.cpp index d431f5343..e98ccfea2 100644 --- a/src/storm/utility/Engine.cpp +++ b/src/storm/utility/Engine.cpp @@ -6,6 +6,7 @@ #include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h" #include "storm/modelchecker/csl/SparseCtmcCslModelChecker.h" #include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" +#include "storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h" #include "storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" #include "storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h" @@ -123,8 +124,9 @@ namespace storm { case ModelType::MA: return storm::modelchecker::SparseMarkovAutomatonCslModelChecker>::canHandleStatic(checkTask); case ModelType::POMDP: - case ModelType::SMG: return false; + case ModelType::SMG: + return storm::modelchecker::SparseSmgRpatlModelChecker>::canHandleStatic(checkTask); } break; case Engine::Hybrid: @@ -177,10 +179,10 @@ namespace storm { return storm::modelchecker::SparseDtmcPrctlModelChecker>::canHandleStatic(checkTask); case ModelType::CTMC: return storm::modelchecker::SparseCtmcCslModelChecker>::canHandleStatic(checkTask); + case ModelType::SMG: case ModelType::MDP: case ModelType::MA: case ModelType::POMDP: - case ModelType::SMG: return false; } break; From d1a0299bd0e21b4806db65ca8b762804f25cf146 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:33:47 +0100 Subject: [PATCH 22/50] buildMatrices handles playerIndices via reference --- src/storm/builder/ExplicitModelBuilder.cpp | 2 +- src/storm/builder/ExplicitModelBuilder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp index 10e0c8927..754568b38 100644 --- a/src/storm/builder/ExplicitModelBuilder.cpp +++ b/src/storm/builder/ExplicitModelBuilder.cpp @@ -120,7 +120,7 @@ namespace storm { } template - void ExplicitModelBuilder::buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianStates, boost::optional> playerActionIndices, boost::optional& stateValuationsBuilder) { + void ExplicitModelBuilder::buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianStates, boost::optional>& playerActionIndices, boost::optional& stateValuationsBuilder) { // Create markovian states bit vector, if required. if (generator->getModelType() == storm::generator::ModelType::MA) { diff --git a/src/storm/builder/ExplicitModelBuilder.h b/src/storm/builder/ExplicitModelBuilder.h index af068b3fa..ed470ca9d 100644 --- a/src/storm/builder/ExplicitModelBuilder.h +++ b/src/storm/builder/ExplicitModelBuilder.h @@ -131,7 +131,7 @@ namespace storm { * @param markovianChoices is set to a bit vector storing whether a choice is Markovian (is only set if the model type requires this information). * @param stateValuationsBuilder if not boost::none, we insert valuations for the corresponding states */ - void buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianChoices, boost::optional> playerActionIndices, boost::optional& stateValuationsBuilder); + void buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianChoices, boost::optional>& playerActionIndices, boost::optional& stateValuationsBuilder); /*! * Explores the state space of the given program and returns the components of the model as a result. From b599ff5c7e4ef3810cd4405e6e34543b88e92764 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:35:50 +0100 Subject: [PATCH 23/50] added sparse MC templates for SMGs --- .../SparsePropositionalModelChecker.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp index cbd135612..a7bc77b77 100644 --- a/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp +++ b/src/storm/modelchecker/propositional/SparsePropositionalModelChecker.cpp @@ -8,6 +8,7 @@ #include "storm/models/sparse/Pomdp.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/sparse/Smg.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" @@ -22,13 +23,13 @@ namespace storm { SparsePropositionalModelChecker::SparsePropositionalModelChecker(SparseModelType const& model) : model(model) { // Intentionally left empty. } - + template bool SparsePropositionalModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); return formula.isInFragment(storm::logic::propositional()); } - + template std::unique_ptr SparsePropositionalModelChecker::checkBooleanLiteralFormula(Environment const& env, CheckTask const& checkTask) { storm::logic::BooleanLiteralFormula const& stateFormula = checkTask.getFormula(); @@ -38,19 +39,19 @@ namespace storm { return std::unique_ptr(new ExplicitQualitativeCheckResult(storm::storage::BitVector(model.getNumberOfStates()))); } } - + template std::unique_ptr SparsePropositionalModelChecker::checkAtomicLabelFormula(Environment const& env, CheckTask const& checkTask) { storm::logic::AtomicLabelFormula const& stateFormula = checkTask.getFormula(); STORM_LOG_THROW(model.hasLabel(stateFormula.getLabel()), storm::exceptions::InvalidPropertyException, "The property refers to unknown label '" << stateFormula.getLabel() << "'."); return std::unique_ptr(new ExplicitQualitativeCheckResult(model.getStates(stateFormula.getLabel()))); } - + template SparseModelType const& SparsePropositionalModelChecker::getModel() const { return model; } - + // Explicitly instantiate the template class. template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; @@ -58,9 +59,11 @@ namespace storm { template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; - + template class SparsePropositionalModelChecker>; + #ifdef STORM_HAVE_CARL template class SparsePropositionalModelChecker>>; + template class SparsePropositionalModelChecker>>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; @@ -68,12 +71,14 @@ namespace storm { template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; + template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; template class SparsePropositionalModelChecker>; + template class SparsePropositionalModelChecker>; #endif } } From 21af5c5d6aaab34c423f476810af3e7c2beef351 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:36:41 +0100 Subject: [PATCH 24/50] handle model description ostream case for SMGs --- src/storm/storage/SymbolicModelDescription.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index abf9aa340..584817ce8 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -229,6 +229,9 @@ namespace storm { case SymbolicModelDescription::ModelType::POMDP: out << "pomdp"; break; + case SymbolicModelDescription::ModelType::SMG: + out << "smg"; + break; } return out; } From 0a65e4aa7bab828345d2eca7e6b10e921837e6dc Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:42:54 +0100 Subject: [PATCH 25/50] verification now handles SMGs --- src/storm/api/verification.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 3e5f916a5..b878a6a7a 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -18,6 +18,7 @@ #include "storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h" #include "storm/modelchecker/exploration/SparseExplorationModelChecker.h" #include "storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" +#include "storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h" #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Mdp.h" @@ -25,6 +26,7 @@ #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/Smg.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" @@ -251,6 +253,28 @@ namespace storm { return verifyWithSparseEngine(env, ma, task); } + template + typename std::enable_if::value, std::unique_ptr>::type verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr> const& smg, storm::modelchecker::CheckTask const& task) { + std::unique_ptr result; + storm::modelchecker::SparseSmgRpatlModelChecker> modelchecker(*smg); + if (modelchecker.canHandle(task)) { + result = modelchecker.check(env, task); + } + return result; + } + + template + typename std::enable_if::value, std::unique_ptr>::type verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr> const& mdp, storm::modelchecker::CheckTask const& task) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify SMGs with this data type."); + } + + template + std::unique_ptr verifyWithSparseEngine(std::shared_ptr> const& smg, storm::modelchecker::CheckTask const& task) { + Environment env; + return verifyWithSparseEngine(env, smg, task); + } + + template std::unique_ptr verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr> const& model, storm::modelchecker::CheckTask const& task) { std::unique_ptr result; @@ -262,6 +286,8 @@ namespace storm { result = verifyWithSparseEngine(env, model->template as>(), task); } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { result = verifyWithSparseEngine(env, model->template as>(), task); + } else if (model->getType() == storm::models::ModelType::Smg) { + result = verifyWithSparseEngine(env, model->template as>(), task); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type " << model->getType() << " is not supported by the sparse engine."); } From 19839036af3c26b3d348e6ceb883f4f0bdcef2ff Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 11:47:01 +0100 Subject: [PATCH 26/50] AbstractMC passes game formula to the rpatl MC --- src/storm/modelchecker/AbstractModelChecker.cpp | 12 ++++++++++++ src/storm/modelchecker/AbstractModelChecker.h | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index 67f03bc9a..8ec5df265 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -15,6 +15,7 @@ #include "storm/models/sparse/Ctmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/Pomdp.h" +#include "storm/models/sparse/Smg.h" #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Ctmc.h" #include "storm/models/symbolic/Mdp.h" @@ -53,6 +54,8 @@ namespace storm { return this->checkMultiObjectiveFormula(env, checkTask.substituteFormula(formula.asMultiObjectiveFormula())); } else if (formula.isQuantileFormula()){ return this->checkQuantileFormula(env, checkTask.substituteFormula(formula.asQuantileFormula())); + } else if(formula.isGameFormula()){ + return this->checkGameFormula(env, checkTask.substituteFormula(formula.asGameFormula())); } STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid."); } @@ -321,6 +324,11 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } + template + std::unique_ptr AbstractModelChecker::checkGameFormula(Environment const& env, CheckTask const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); + } + /////////////////////////////////////////////// // Explicitly instantiate the template class. /////////////////////////////////////////////// @@ -331,9 +339,11 @@ namespace storm { template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; + template class AbstractModelChecker>; #ifdef STORM_HAVE_CARL template class AbstractModelChecker>>; + template class AbstractModelChecker>>; template class AbstractModelChecker>; template class AbstractModelChecker>; @@ -341,12 +351,14 @@ namespace storm { template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; + template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; template class AbstractModelChecker>; + template class AbstractModelChecker>; #endif // DD template class AbstractModelChecker>; diff --git a/src/storm/modelchecker/AbstractModelChecker.h b/src/storm/modelchecker/AbstractModelChecker.h index 80bf18fb6..59149711c 100644 --- a/src/storm/modelchecker/AbstractModelChecker.h +++ b/src/storm/modelchecker/AbstractModelChecker.h @@ -88,13 +88,15 @@ namespace storm { virtual std::unique_ptr checkTimeOperatorFormula(Environment const& env, CheckTask const& checkTask); virtual std::unique_ptr checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask); virtual std::unique_ptr checkUnaryBooleanStateFormula(Environment const& env, CheckTask const& checkTask); - + // The methods to check multi-objective formulas. virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask); - + // The methods to check quantile formulas. virtual std::unique_ptr checkQuantileFormula(Environment const& env, CheckTask const& checkTask); - + + // The methods to check game formulas. + virtual std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask); }; } } From 0a689d232ed2da52bb528c512a7f46f02e67edfc Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 12:15:16 +0100 Subject: [PATCH 27/50] init helper for games --- ...deterministicGameInfiniteHorizonHelper.cpp | 56 ++++++++++++++++ ...ondeterministicGameInfiniteHorizonHelper.h | 66 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp create mode 100644 src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp new file mode 100644 index 000000000..baaa3782d --- /dev/null +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp @@ -0,0 +1,56 @@ +#include "SparseNondeterministicGameInfiniteHorizonHelper.h" + +#include "storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h" + +#include "storm/storage/SparseMatrix.h" +#include "storm/storage/Scheduler.h" + +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" + +#include "storm/utility/solver.h" +#include "storm/utility/vector.h" + +#include "storm/environment/solver/LongRunAverageSolverEnvironment.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" + +#include "storm/exceptions/UnmetRequirementException.h" +#include "storm/exceptions/InternalException.h" + +namespace storm { + namespace modelchecker { + namespace helper { + + template + SparseNondeterministicGameInfiniteHorizonHelper::SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& coalitionIndices) : SparseInfiniteHorizonHelper(transitionMatrix), coalitionIndices(coalitionIndices) { + // Intentionally left empty. + } + + template + void SparseNondeterministicGameInfiniteHorizonHelper::createDecomposition() { + STORM_LOG_THROW(false, storm::exceptions::InternalException, "Creating Decompositions of SMGs is currently not possible."); + } + + template + ValueType SparseNondeterministicGameInfiniteHorizonHelper::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) { + + STORM_LOG_THROW(false, storm::exceptions::InternalException, "Computing values for LRA for SMGs components is currently not possible."); + } + + template + std::vector SparseNondeterministicGameInfiniteHorizonHelper::buildAndSolveSsp(Environment const& env, std::vector const& componentLraValues) { + STORM_LOG_THROW(false, storm::exceptions::InternalException, "buildAndSolveSsp not available for SMGs"); + } + + template + std::vector SparseNondeterministicGameInfiniteHorizonHelper::computeLongRunAverageValues(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter) { + STORM_LOG_THROW(false, storm::exceptions::InternalException, "computeLongRunAverageValues not possible yet."); + } + + + template class SparseNondeterministicGameInfiniteHorizonHelper; + template class SparseNondeterministicGameInfiniteHorizonHelper; + + } + } +} diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h new file mode 100644 index 000000000..550d12a47 --- /dev/null +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h @@ -0,0 +1,66 @@ +#pragma once +#include "storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h" + +namespace storm { + + namespace storage { + template class Scheduler; + } + + namespace modelchecker { + namespace helper { + + /*! + * Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system with different players choices. + * @tparam ValueType the type a value can have + */ + template + class SparseNondeterministicGameInfiniteHorizonHelper : public SparseInfiniteHorizonHelper { + + public: + + /*! + * Function mapping from indices to values + */ + typedef typename SparseInfiniteHorizonHelper::ValueGetter ValueGetter; + + /*! + * Initializes the helper for a discrete time model with different players (i.e. SMG) + */ + SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& coalitionIndices); + + /*! + * TODO + */ + std::vector computeLongRunAverageValues(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter); + + /*! + * @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. + */ + //std::vector const& getProducedOptimalChoices() const; + + /*! + * @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. + */ + //std::vector& getProducedOptimalChoices(); + + /*! + * @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. + */ + //storm::storage::Scheduler extractScheduler() const; + + void createDecomposition(); + ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component); + std::vector buildAndSolveSsp(Environment const& env, std::vector const& mecLraValues); + + private: + std::vector coalitionIndices; + }; + + + } + } +} From af38bc3b4da679e589084de10628f3bc97f6ab76 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 16 Dec 2020 12:45:36 +0100 Subject: [PATCH 28/50] added transition type for games to LraViHelper --- .../helper/infinitehorizon/internal/LraViHelper.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h index bbf9207a4..db1a30a01 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h @@ -25,9 +25,10 @@ namespace storm { DetTsNoIs, /// deterministic choice at timed states, no instant states (as in DTMCs and CTMCs) DetTsNondetIs, /// deterministic choice at timed states, nondeterministic choice at instant states (as in Markov Automata) DetTsDetIs, /// deterministic choice at timed states, deterministic choice at instant states (as in Markov Automata without any nondeterminisim) - NondetTsNoIs /// nondeterministic choice at timed states, no instant states (as in MDPs) + NondetTsNoIs, /// nondeterministic choice at timed states, no instant states (as in MDPs) + GameNondetTsNoIs // nondeterministic choices of different players at timed states, no instant states (as in SMGs) }; - + /*! * Helper class that performs iterations of the value iteration method. * The purpose of the template parameters ComponentType and TransitionsType are used to make this work for various model types. From c11c49d22bec8fd878949ccb15eaac3e4665e006 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 15:58:30 +0100 Subject: [PATCH 29/50] store tuples of player name and index Store this instead of only the index. Needed for easier parsing of the rpatl formulas (prism allows player indices and names!) --- src/storm/builder/ExplicitModelBuilder.cpp | 10 +++++----- src/storm/builder/ExplicitModelBuilder.h | 2 +- src/storm/generator/Choice.cpp | 12 ++++++------ src/storm/generator/Choice.h | 10 +++++----- src/storm/generator/PrismNextStateGenerator.cpp | 14 ++++++++------ src/storm/logic/Coalition.cpp | 6 +++++- src/storm/logic/Coalition.h | 6 ++++-- ...seNondeterministicGameInfiniteHorizonHelper.cpp | 2 +- ...arseNondeterministicGameInfiniteHorizonHelper.h | 4 ++-- src/storm/models/sparse/Smg.cpp | 2 +- src/storm/models/sparse/Smg.h | 4 ++-- src/storm/storage/sparse/ModelComponents.h | 6 +++--- 12 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp index 754568b38..3e224a419 100644 --- a/src/storm/builder/ExplicitModelBuilder.cpp +++ b/src/storm/builder/ExplicitModelBuilder.cpp @@ -120,7 +120,7 @@ namespace storm { } template - void ExplicitModelBuilder::buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianStates, boost::optional>& playerActionIndices, boost::optional& stateValuationsBuilder) { + void ExplicitModelBuilder::buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianStates, boost::optional>>& playerActionIndices, boost::optional& stateValuationsBuilder) { // Create markovian states bit vector, if required. if (generator->getModelType() == storm::generator::ModelType::MA) { @@ -130,7 +130,7 @@ namespace storm { // Create the player indices vector, if required. if (generator->getModelType() == storm::generator::ModelType::SMG) { - playerActionIndices = std::vector{}; + playerActionIndices = std::vector>{}; playerActionIndices.get().reserve(1000); } @@ -211,7 +211,7 @@ namespace storm { if (playerActionIndices) { // TODO change this to storm::utility::infinity() ? - playerActionIndices.get().push_back(-1); + playerActionIndices.get().emplace_back("", -1); } ++currentRow; @@ -270,7 +270,7 @@ namespace storm { } if (playerActionIndices) { - playerActionIndices.get().push_back(behavior.getChoices().at(0).getPlayerIndex()); + playerActionIndices.get().push_back(behavior.getChoices().at(0).getPlayer()); } ++currentRowGroup; } @@ -350,7 +350,7 @@ namespace storm { } ChoiceInformationBuilder choiceInformationBuilder; boost::optional markovianStates; - boost::optional> playerActionIndices; + boost::optional>> playerActionIndices; // If we need to build state valuations, initialize them now. boost::optional stateValuationsBuilder; diff --git a/src/storm/builder/ExplicitModelBuilder.h b/src/storm/builder/ExplicitModelBuilder.h index ed470ca9d..7b1fee8a8 100644 --- a/src/storm/builder/ExplicitModelBuilder.h +++ b/src/storm/builder/ExplicitModelBuilder.h @@ -131,7 +131,7 @@ namespace storm { * @param markovianChoices is set to a bit vector storing whether a choice is Markovian (is only set if the model type requires this information). * @param stateValuationsBuilder if not boost::none, we insert valuations for the corresponding states */ - void buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianChoices, boost::optional>& playerActionIndices, boost::optional& stateValuationsBuilder); + void buildMatrices(storm::storage::SparseMatrixBuilder& transitionMatrixBuilder, std::vector>& rewardModelBuilders, ChoiceInformationBuilder& choiceInformationBuilder, boost::optional& markovianChoices, boost::optional>>& playerActionIndices, boost::optional& stateValuationsBuilder); /*! * Explores the state space of the given program and returns the components of the model as a result. diff --git a/src/storm/generator/Choice.cpp b/src/storm/generator/Choice.cpp index 517dffd6c..9abde728b 100644 --- a/src/storm/generator/Choice.cpp +++ b/src/storm/generator/Choice.cpp @@ -93,18 +93,18 @@ namespace storm { } template - void Choice::setPlayerIndex(uint_fast32_t playerIndex) { - this->playerIndex = playerIndex; + void Choice::setPlayer(std::pair player) { + this->player = player; } template - bool Choice::hasPlayerIndex() const { - return playerIndex.is_initialized(); + bool Choice::hasPlayer() const { + return player.is_initialized(); } template - uint_fast32_t const& Choice::getPlayerIndex() const { - return playerIndex.get(); + std::pair const& Choice::getPlayer() const { + return player.get(); } template diff --git a/src/storm/generator/Choice.h b/src/storm/generator/Choice.h index 80f8f7031..65945b8d1 100644 --- a/src/storm/generator/Choice.h +++ b/src/storm/generator/Choice.h @@ -96,19 +96,19 @@ namespace storm { * * @param The player index associated with this choice. */ - void setPlayerIndex(uint_fast32_t playerIndex); + void setPlayer(std::pair player); /*! * Returns whether there is an index for the player defined for this choice. */ - bool hasPlayerIndex() const; + bool hasPlayer() const; /*! * Retrieves the players index associated with this choice * * @return The player index associated with this choice. */ - uint_fast32_t const& getPlayerIndex() const; + std::pair const& getPlayer() const; /*! * Adds the given data that specifies the origin of this choice w.r.t. the model specification @@ -196,8 +196,8 @@ namespace storm { // The labels of this choice boost::optional> labels; - // The playerIndex of this choice - boost::optional playerIndex = boost::none; + // The player of this choice + boost::optional> player = boost::none; }; template diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 03b4975a6..0d8ed6cd5 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -83,7 +83,7 @@ namespace storm { if (program.getModelType() == storm::prism::Program::ModelType::SMG) { for (auto const& player : program.getPlayers()) { - uint_fast32_t playerIndex = program.getIndexOfPlayer(player.getName()); + uint_fast64_t playerIndex = program.getIndexOfPlayer(player.getName()); for (auto const& moduleIndexPair : player.getModules()) { moduleIndexToPlayerIndexMap[moduleIndexPair.second] = playerIndex; } @@ -382,12 +382,12 @@ namespace storm { } if (program.getModelType() == storm::prism::Program::ModelType::SMG) { - uint_fast32_t statePlayerIndex = allChoices.at(0).getPlayerIndex(); + uint_fast64_t statePlayerIndex = allChoices.at(0).getPlayer().second; for(auto& choice : allChoices) { if (allChoices.size() == 1) break; // getPlayerIndex().is_initialized()? - if (choice.hasPlayerIndex()) { - STORM_LOG_ASSERT(choice.getPlayerIndex() == statePlayerIndex, "State '" << this->stateToString(*this->state) << "' comprises choices for different players."); + if (choice.hasPlayer()) { + STORM_LOG_ASSERT(choice.getPlayer().second == statePlayerIndex, "State '" << this->stateToString(*this->state) << "' comprises choices for different players."); } else { STORM_LOG_WARN("State '" << this->stateToString(*this->state) << "' features a choice without player index."); } @@ -612,7 +612,8 @@ namespace storm { if (program.getModelType() == storm::prism::Program::ModelType::SMG) { // Can we trust the model ordering here? // I.e. is i the correct moduleIndex set in Program.cpp:805? TODO - choice.setPlayerIndex(moduleIndexToPlayerIndexMap[i]); + uint_fast64_t playerIndex = moduleIndexToPlayerIndexMap[i]; + choice.setPlayer(std::make_pair(program.getPlayers()[playerIndex].getName(), playerIndex)); } if (this->options.isExplorationChecksSet()) { @@ -678,7 +679,8 @@ namespace storm { Choice& choice = choices.back(); if (program.getModelType() == storm::prism::Program::ModelType::SMG) { - choice.setPlayerIndex(commandIndexToPlayerIndexMap[actionIndex]); + uint_fast64_t playerIndex = commandIndexToPlayerIndexMap[actionIndex]; + choice.setPlayer(std::make_pair(program.getPlayers()[playerIndex].getName(), playerIndex)); } // Remember the choice label and origins only if we were asked to. diff --git a/src/storm/logic/Coalition.cpp b/src/storm/logic/Coalition.cpp index 0781aaece..baa0736c4 100644 --- a/src/storm/logic/Coalition.cpp +++ b/src/storm/logic/Coalition.cpp @@ -3,10 +3,14 @@ namespace storm { namespace logic { - Coalition::Coalition(std::vector> playerIds) : playerIds(playerIds) { + Coalition::Coalition(std::vector> playerIds) : playerIds(playerIds) { // Intentionally left empty. } + std::vector> Coalition::getPlayerIds() const { + return playerIds; + } + std::ostream& operator<<(std::ostream& stream, Coalition const& coalition) { bool firstItem = true; stream << "<<"; diff --git a/src/storm/logic/Coalition.h b/src/storm/logic/Coalition.h index 73ea92ac4..9f3966dd1 100644 --- a/src/storm/logic/Coalition.h +++ b/src/storm/logic/Coalition.h @@ -15,13 +15,15 @@ namespace storm { class Coalition { public: Coalition() = default; - Coalition(std::vector>); + Coalition(std::vector>); Coalition(Coalition const& other) = default; + std::vector> getPlayerIds() const; + friend std::ostream& operator<<(std::ostream& stream, Coalition const& coalition); private: - std::vector> playerIds; + std::vector> playerIds; }; } } diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp index baaa3782d..03538c2e9 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp @@ -22,7 +22,7 @@ namespace storm { namespace helper { template - SparseNondeterministicGameInfiniteHorizonHelper::SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& coalitionIndices) : SparseInfiniteHorizonHelper(transitionMatrix), coalitionIndices(coalitionIndices) { + SparseNondeterministicGameInfiniteHorizonHelper::SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector> const& player) : SparseInfiniteHorizonHelper(transitionMatrix), player(player) { // Intentionally left empty. } diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h index 550d12a47..fd872b807 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h @@ -27,7 +27,7 @@ namespace storm { /*! * Initializes the helper for a discrete time model with different players (i.e. SMG) */ - SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& coalitionIndices); + SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector> const& player); /*! * TODO @@ -57,7 +57,7 @@ namespace storm { std::vector buildAndSolveSsp(Environment const& env, std::vector const& mecLraValues); private: - std::vector coalitionIndices; + std::vector> player; }; diff --git a/src/storm/models/sparse/Smg.cpp b/src/storm/models/sparse/Smg.cpp index e7c20c9fa..f6b75a447 100644 --- a/src/storm/models/sparse/Smg.cpp +++ b/src/storm/models/sparse/Smg.cpp @@ -39,7 +39,7 @@ namespace storm { } template - std::vector Smg::getPlayerActionIndices() const { + std::vector> Smg::getPlayerActionIndices() const { return playerActionIndices; } diff --git a/src/storm/models/sparse/Smg.h b/src/storm/models/sparse/Smg.h index 2bf7146c8..30334adda 100644 --- a/src/storm/models/sparse/Smg.h +++ b/src/storm/models/sparse/Smg.h @@ -49,10 +49,10 @@ namespace storm { Smg(Smg&& other) = default; Smg& operator=(Smg&& other) = default; - std::vector getPlayerActionIndices() const; + std::vector> getPlayerActionIndices() const; private: - std::vector playerActionIndices; + std::vector> playerActionIndices; }; } // namespace sparse diff --git a/src/storm/storage/sparse/ModelComponents.h b/src/storm/storage/sparse/ModelComponents.h index 29ae3d14b..580732380 100644 --- a/src/storm/storage/sparse/ModelComponents.h +++ b/src/storm/storage/sparse/ModelComponents.h @@ -31,7 +31,7 @@ namespace storm { bool rateTransitions = false, boost::optional const& markovianStates = boost::none, boost::optional> const& player1Matrix = boost::none, - boost::optional> const& playerActionIndices = boost::none) + boost::optional>> const& playerActionIndices = boost::none) : transitionMatrix(transitionMatrix), stateLabeling(stateLabeling), rewardModels(rewardModels), rateTransitions(rateTransitions), markovianStates(markovianStates), player1Matrix(player1Matrix), playerActionIndices(playerActionIndices) { // Intentionally left empty } @@ -42,7 +42,7 @@ namespace storm { bool rateTransitions = false, boost::optional&& markovianStates = boost::none, boost::optional>&& player1Matrix = boost::none, - boost::optional>&& playerActionIndices = boost::none) + boost::optional>>&& playerActionIndices = boost::none) : transitionMatrix(std::move(transitionMatrix)), stateLabeling(std::move(stateLabeling)), rewardModels(std::move(rewardModels)), rateTransitions(rateTransitions), markovianStates(std::move(markovianStates)), player1Matrix(std::move(player1Matrix)), playerActionIndices(std::move(playerActionIndices)) { // Intentionally left empty } @@ -85,7 +85,7 @@ namespace storm { // Stochastic multiplayer game specific components: // The vector mapping state choices to players - boost::optional> playerActionIndices; + boost::optional>> playerActionIndices; }; } } From 9ef1ec5f5093193b3b92c5a35dea318925f993cb Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:07:02 +0100 Subject: [PATCH 30/50] added opt dir override bitvector to multiplier This is mainly used by the SMG model checker to override row group optimization directions. --- .../solver/MultiplierEnvironment.cpp | 20 +++++--- .../solver/MultiplierEnvironment.h | 18 +++++-- src/storm/solver/Multiplier.cpp | 34 ++++++++----- src/storm/solver/Multiplier.h | 51 ++++++++++++------- 4 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/storm/environment/solver/MultiplierEnvironment.cpp b/src/storm/environment/solver/MultiplierEnvironment.cpp index 85e3bac77..0dd7f031a 100644 --- a/src/storm/environment/solver/MultiplierEnvironment.cpp +++ b/src/storm/environment/solver/MultiplierEnvironment.cpp @@ -6,28 +6,36 @@ #include "storm/utility/macros.h" namespace storm { - + MultiplierEnvironment::MultiplierEnvironment() { auto const& multiplierSettings = storm::settings::getModule(); type = multiplierSettings.getMultiplierType(); typeSetFromDefault = multiplierSettings.isMultiplierTypeSetFromDefaultValue(); } - + MultiplierEnvironment::~MultiplierEnvironment() { // Intentionally left empty } - + storm::solver::MultiplierType const& MultiplierEnvironment::getType() const { return type; } - + bool const& MultiplierEnvironment::isTypeSetFromDefault() const { return typeSetFromDefault; } - + void MultiplierEnvironment::setType(storm::solver::MultiplierType value, bool isSetFromDefault) { type = value; typeSetFromDefault = isSetFromDefault; } - + + void MultiplierEnvironment::setOptimizationDirectionOverride(storm::storage::BitVector optDirOverride) { + optimizationDirectionOverride = optDirOverride; + } + + boost::optional const& MultiplierEnvironment::getOptimizationDirectionOverride() const { + return optimizationDirectionOverride; + } + } diff --git a/src/storm/environment/solver/MultiplierEnvironment.h b/src/storm/environment/solver/MultiplierEnvironment.h index d9e35f5fb..945b62602 100644 --- a/src/storm/environment/solver/MultiplierEnvironment.h +++ b/src/storm/environment/solver/MultiplierEnvironment.h @@ -1,23 +1,31 @@ #pragma once +#include + #include "storm/environment/solver/SolverEnvironment.h" #include "storm/solver/SolverSelectionOptions.h" +#include "storm/storage/BitVector.h" + namespace storm { - + class MultiplierEnvironment { public: - + MultiplierEnvironment(); ~MultiplierEnvironment(); - + storm::solver::MultiplierType const& getType() const; bool const& isTypeSetFromDefault() const; void setType(storm::solver::MultiplierType value, bool isSetFromDefault = false); - + + void setOptimizationDirectionOverride(storm::storage::BitVector optimizationDirectionOverride); + boost::optional const& getOptimizationDirectionOverride() const; + private: storm::solver::MultiplierType type; bool typeSetFromDefault; + + boost::optional optimizationDirectionOverride = boost::none; }; } - diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 4049b56ca..87e74b16a 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -18,17 +18,17 @@ namespace storm { namespace solver { - + template Multiplier::Multiplier(storm::storage::SparseMatrix const& matrix) : matrix(matrix) { // Intentionally left empty. } - + template void Multiplier::clearCache() const { cachedVector.reset(); } - + template void Multiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { multiplyAndReduce(env, dir, this->matrix.getRowGroupIndices(), x, b, result, choices); @@ -38,7 +38,7 @@ namespace storm { void Multiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices, bool backwards) const { multiplyAndReduceGaussSeidel(env, dir, this->matrix.getRowGroupIndices(), x, b, choices, backwards); } - + template void Multiplier::repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const { storm::utility::ProgressMeasurement progress("multiplications"); @@ -53,7 +53,7 @@ namespace storm { } } } - + template void Multiplier::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const { storm::utility::ProgressMeasurement progress("multiplications"); @@ -67,17 +67,27 @@ namespace storm { } } } - + template void Multiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { multiplyRow(rowIndex, x1, val1); multiplyRow(rowIndex, x2, val2); } - + + template + void Multiplier::setOptimizationDirectionOverride(storm::storage::BitVector const& optDirOverride) { + optimizationDirectionOverride = optDirOverride; + } + + template + boost::optional Multiplier::getOptimizationDirectionOverride() const { + return optimizationDirectionOverride; + } + template std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { auto type = env.solver().multiplier().getType(); - + // Adjust the multiplier type if an eqsolver was specified but not a multiplier if (!env.solver().isLinearEquationSolverTypeSetFromDefaultValue() && env.solver().multiplier().isTypeSetFromDefault()) { bool changed = false; @@ -90,7 +100,7 @@ namespace storm { } STORM_LOG_INFO_COND(!changed, "Selecting '" + toString(type) + "' as the multiplier type to match the selected equation solver. If you want to override this, please explicitly specify a different multiplier type."); } - + switch (type) { case MultiplierType::Gmmxx: return std::make_unique>(matrix); @@ -99,16 +109,16 @@ namespace storm { } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown MultiplierType"); } - + template class Multiplier; template class MultiplierFactory; - + #ifdef STORM_HAVE_CARL template class Multiplier; template class MultiplierFactory; template class Multiplier; template class MultiplierFactory; #endif - + } } diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 58aeb4e38..552a427dd 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -2,34 +2,37 @@ #include #include +#include + +#include "storm/storage/BitVector.h" #include "storm/solver/OptimizationDirection.h" #include "storm/solver/MultiplicationStyle.h" namespace storm { - + class Environment; - + namespace storage { template class SparseMatrix; } - + namespace solver { - + template class Multiplier { public: - + Multiplier(storm::storage::SparseMatrix const& matrix); - + virtual ~Multiplier() = default; - + /* * Clears the currently cached data of this multiplier in order to free some memory. */ virtual void clearCache() const; - + /*! * Performs a matrix-vector multiplication x' = A*x + b. * @@ -41,7 +44,7 @@ namespace storm { * to the number of rows of A. Can be the same as the x vector. */ virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const = 0; - + /*! * Performs a matrix-vector multiplication in gauss-seidel style. * @@ -52,7 +55,7 @@ namespace storm { * @param backwards if true, the iterations will be performed beginning from the last row and ending at the first row. */ virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b, bool backwards = true) const = 0; - + /*! * Performs a matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups * so that the resulting vector has the size of number of row groups of A. @@ -69,7 +72,7 @@ namespace storm { */ void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; - + /*! * Performs a matrix-vector multiplication in gauss-seidel style and then minimizes/maximizes over the row groups * so that the resulting vector has the size of number of row groups of A. @@ -87,7 +90,7 @@ namespace storm { */ void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices = nullptr, bool backwards = true) const; virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr, bool backwards = true) const = 0; - + /*! * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After * performing the necessary multiplications, the result is written to the input vector x. Note that the @@ -100,7 +103,7 @@ namespace storm { * @param n The number of times to perform the multiplication. */ void repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const; - + /*! * Performs repeated matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups * so that the resulting vector has the size of number of row groups of A. @@ -115,7 +118,7 @@ namespace storm { * @param n The number of times to perform the multiplication. */ void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const; - + /*! * Multiplies the row with the given index with x and adds the result to the provided value * @param rowIndex The index of the considered row @@ -123,7 +126,7 @@ namespace storm { * @param value The multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. */ virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const = 0; - + /*! * Multiplies the row with the given index with x1 and x2 and adds the given offset o1 and o2, respectively * @param rowIndex The index of the considered row @@ -133,12 +136,24 @@ namespace storm { * @param val2 The second multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. */ virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const; - + + /* + * TODO + */ + void setOptimizationDirectionOverride(storm::storage::BitVector const& optimizationDirectionOverride); + + /* + * TODO + */ + boost::optional getOptimizationDirectionOverride() const; + protected: mutable std::unique_ptr> cachedVector; storm::storage::SparseMatrix const& matrix; + + boost::optional optimizationDirectionOverride = boost::none; }; - + template class MultiplierFactory { public: @@ -147,6 +162,6 @@ namespace storm { std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix); }; - + } } From b61d947057c16d196f9b5127055cd186cb42f939 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:10:05 +0100 Subject: [PATCH 31/50] parse coalition operator and set row group optdirs --- .../rpatl/SparseSmgRpatlModelChecker.cpp | 28 +++++++++++++++++++ .../rpatl/SparseSmgRpatlModelChecker.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp index f6161fac2..a6c230625 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -110,6 +110,34 @@ namespace storm { //std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values)); //return result; STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "NYI"); + template + void SparseSmgRpatlModelChecker::coalitionIndicator(Environment& env, CheckTask const& checkTask) { + storm::storage::BitVector coalitionIndicators(this->getModel().getTransitionMatrix().getRowGroupCount()); + + std::vector> formulaPlayerIds = checkTask.getFormula().getCoalition().getPlayerIds(); + std::vector playerIds; + std::vector> playerActionIndices = this->getModel().getPlayerActionIndices(); + + for(auto const& player : formulaPlayerIds) { + // If the player is given via the player name we have to look up its index + if(player.type() == typeid(std::string)) { + auto it = std::find_if(playerActionIndices.begin(), playerActionIndices.end(), + [&player](const std::pair& element){ return element.first == boost::get(player); }); + playerIds.push_back(it->second); + // If the player is given by its index we have to shift it to match internal mappings + } else if(player.type() == typeid(uint_fast64_t)) { + playerIds.push_back(boost::get(player) - 1); + } + } + + for(uint i = 0; i < playerActionIndices.size(); i++) { + if(std::find(playerIds.begin(), playerIds.end(), playerActionIndices.at(i).second) != playerIds.end()) { + coalitionIndicators.set(i); + } + } + coalitionIndicators.complement(); + + env.solver().multiplier().setOptimizationDirectionOverride(coalitionIndicators); } template class SparseSmgRpatlModelChecker>; diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h index 91bb09206..0927fc618 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h @@ -31,6 +31,8 @@ namespace storm { virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + + void coalitionIndicator(Environment& env, CheckTask const& checkTask); }; } // namespace modelchecker } // namespace storm From f72f83f23e99d468a316729f52eca261e26e789c Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:34:00 +0100 Subject: [PATCH 32/50] computeLongRunAverageValues is now virtual in SparseInfiniteHorizonHelper, since SparseNondeterministicGameInfiniteHorizonHelper needs to overwrite it. --- .../helper/infinitehorizon/SparseInfiniteHorizonHelper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h b/src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h index 6630dd5ad..5b8ed6419 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h @@ -93,8 +93,8 @@ namespace storm { * @param actionValuesGetter a function returning a value for a given (global) choice index * @return a value for each state */ - std::vector computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter); - + virtual std::vector computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter); + /*! * @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 From ea90c1ac7d96c766c1e4569bb601d3f5c46eeab5 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:30:40 +0100 Subject: [PATCH 33/50] added and finalized methods for rpatlMC --- .../rpatl/SparseSmgRpatlModelChecker.cpp | 65 +++++++++++-------- .../rpatl/SparseSmgRpatlModelChecker.h | 14 ++-- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp index a6c230625..3b217030e 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include "storm/utility/macros.h" #include "storm/utility/FilteredRewardModel.h" @@ -14,6 +16,10 @@ #include "storm/modelchecker/helper/utility/SetInformationFromCheckTask.h" #include "storm/logic/FragmentSpecification.h" +#include "storm/logic/Coalition.h" + +#include "storm/storage/BitVector.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -30,10 +36,11 @@ namespace storm { // Intentionally left empty. } + + template bool SparseSmgRpatlModelChecker::canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::rpatl().setCoalitionOperatorsAllowed(true).setRewardOperatorsAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageOperatorsAllowed(true))) { return true; } else { @@ -51,21 +58,22 @@ namespace storm { } } + + template std::unique_ptr SparseSmgRpatlModelChecker::checkGameFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_DEBUG("checkGameFormula matrix: " << this->getModel().getTransitionMatrix().getDimensionsAsString()); - STORM_LOG_DEBUG("checkGameFormula playerindices:"); - STORM_LOG_DEBUG("checkGameFormula matrix: \n" << this->getModel().getTransitionMatrix()); - // TODO set min max row groups w.r.t. coalition + Environment solverEnv = env; + coalitionIndicator(solverEnv, checkTask); + storm::logic::GameFormula const& gameFormula = checkTask.getFormula(); storm::logic::Formula const& subFormula = gameFormula.getSubformula(); - STORM_LOG_DEBUG(gameFormula); + if (subFormula.isRewardOperatorFormula()) { - return this->checkRewardOperatorFormula(env, checkTask.substituteFormula(subFormula.asRewardOperatorFormula())); + return this->checkRewardOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asRewardOperatorFormula())); } else if (subFormula.isLongRunAverageOperatorFormula()) { - return this->checkLongRunAverageOperatorFormula(env, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula())); + return this->checkLongRunAverageOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula())); } - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "checkGameFormula NYI"); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Cannot check this property (yet)."); } template @@ -73,26 +81,26 @@ namespace storm { storm::logic::RewardOperatorFormula const& formula = checkTask.getFormula(); std::unique_ptr result = this->computeRewards(env, formula.getMeasureType(), checkTask.substituteFormula(formula.getSubformula())); - return nullptr; + return result; } template - std::unique_ptr AbstractModelChecker::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - storm::logic::Formula const& rewardFormula = checkTask.getFormula(); - if (rewardFormula.isLongRunAverageRewardFormula()) { - return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); - } - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' is invalid."); + std::unique_ptr SparseSmgRpatlModelChecker::checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask) { + storm::logic::LongRunAverageOperatorFormula const& formula = checkTask.getFormula(); + std::unique_ptr result = this->computeLongRunAverageProbabilities(env, checkTask.substituteFormula(formula.getSubformula().asStateFormula())); + + return result; } - template - std::unique_ptr AbstractModelChecker::checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask) { - storm::logic::LongRunAverageOperatorFormula const& formula = checkTask.getFormula(); - //STORM_LOG_THROW(formula.getSubformula().isStateFormula(), storm::exceptions::InvalidArgumentException, "The given formula is invalid."); - std::unique_ptr result = this->computeLongRunAverageProbabilities(env, checkTask.substituteFormula(formula.getSubformula().asStateFormula())); - return result; //TODO check bounds. + template + std::unique_ptr SparseSmgRpatlModelChecker::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { + storm::logic::Formula const& rewardFormula = checkTask.getFormula(); + if (rewardFormula.isLongRunAverageRewardFormula()) { + return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' cannot (yet) be handled."); } template @@ -107,9 +115,15 @@ namespace storm { storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); - //std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values)); - //return result; - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "NYI"); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values))); + if (checkTask.isProduceSchedulersSet()) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::make_unique>(helper.extractScheduler())); + } + return result; + } + + + template void SparseSmgRpatlModelChecker::coalitionIndicator(Environment& env, CheckTask const& checkTask) { storm::storage::BitVector coalitionIndicators(this->getModel().getTransitionMatrix().getRowGroupCount()); @@ -143,7 +157,6 @@ namespace storm { template class SparseSmgRpatlModelChecker>; #ifdef STORM_HAVE_CARL template class SparseSmgRpatlModelChecker>; - //template class SparseSmgRpatlModelChecker>; TODO are we going to need this? #endif } } diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h index 0927fc618..9a194dbb7 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h @@ -25,12 +25,14 @@ namespace storm { static bool canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState = nullptr); // The implemented methods of the AbstractModelChecker interface. - virtual bool canHandle(CheckTask const& checkTask) const override; - virtual std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask) override; - virtual std::unique_ptr checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) override; - - virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; - virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + bool canHandle(CheckTask const& checkTask) const override; + std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask) override; + std::unique_ptr checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) override; + std::unique_ptr checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask) override; + + std::unique_ptr computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; + std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; void coalitionIndicator(Environment& env, CheckTask const& checkTask); }; From 4c7968b4cf8db8d6e825c340ecc0e2c402c4b4a9 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:41:47 +0100 Subject: [PATCH 34/50] added and finalized NondetGamehelper methods This still needs some better documentation for the introduced class methods. Also removed some debug printing. --- src/storm-parsers/parser/PrismParser.cpp | 1 - ...deterministicGameInfiniteHorizonHelper.cpp | 89 +++++++++++++++++-- ...ondeterministicGameInfiniteHorizonHelper.h | 21 +++-- 3 files changed, 96 insertions(+), 15 deletions(-) diff --git a/src/storm-parsers/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp index 624dda819..23a3b3464 100644 --- a/src/storm-parsers/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -816,7 +816,6 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": No action named '" << actionName << "' present."); } } - STORM_LOG_DEBUG("PLAYER created:" << playerName); return storm::prism::Player(playerName, controlledModuleIndices, controlledActionIndices); } else { return storm::prism::Player(); diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp index 03538c2e9..d48211af6 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp @@ -3,6 +3,7 @@ #include "storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/MaximalEndComponentDecomposition.h" #include "storm/storage/Scheduler.h" #include "storm/solver/MinMaxLinearEquationSolver.h" @@ -26,25 +27,99 @@ namespace storm { // Intentionally left empty. } + template + std::vector const& SparseNondeterministicGameInfiniteHorizonHelper::getProducedOptimalChoices() const { + 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?"); + return this->_producedOptimalChoices.get(); + } + + template + std::vector& SparseNondeterministicGameInfiniteHorizonHelper::getProducedOptimalChoices() { + 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?"); + return this->_producedOptimalChoices.get(); + } + + template + storm::storage::Scheduler SparseNondeterministicGameInfiniteHorizonHelper::extractScheduler() const { + auto const& optimalChoices = getProducedOptimalChoices(); + storm::storage::Scheduler scheduler(optimalChoices.size()); + for (uint64_t state = 0; state < optimalChoices.size(); ++state) { + scheduler.setChoice(optimalChoices[state], state); + } + return scheduler; + } + + template void SparseNondeterministicGameInfiniteHorizonHelper::createDecomposition() { - STORM_LOG_THROW(false, storm::exceptions::InternalException, "Creating Decompositions of SMGs is currently not possible."); + // TODO This needs to be changed to return the whole model as one component as long as there is no overwritten version of MaximalEndComponentDecomposition for SMGs. + if (this->_longRunComponentDecomposition == nullptr) { + // The decomposition has not been provided or computed, yet. + if (this->_backwardTransitions == nullptr) { + this->_computedBackwardTransitions = std::make_unique>(this->_transitionMatrix.transpose(true)); + this->_backwardTransitions = this->_computedBackwardTransitions.get(); + } + this->_computedLongRunComponentDecomposition = std::make_unique>(this->_transitionMatrix, *this->_backwardTransitions); + this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get(); + } } template - ValueType SparseNondeterministicGameInfiniteHorizonHelper::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) { + std::vector SparseNondeterministicGameInfiniteHorizonHelper::computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) { + auto underlyingSolverEnvironment = env; + std::vector componentLraValues; + createDecomposition(); + componentLraValues.reserve(this->_longRunComponentDecomposition->size()); + for (auto const& c : *(this->_longRunComponentDecomposition)) { + componentLraValues.push_back(computeLraForComponent(underlyingSolverEnvironment, stateValuesGetter, actionValuesGetter, c)); + } + return componentLraValues; + } - STORM_LOG_THROW(false, storm::exceptions::InternalException, "Computing values for LRA for SMGs components is currently not possible."); + template + ValueType SparseNondeterministicGameInfiniteHorizonHelper::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) { + // Allocate memory for the nondeterministic choices. + if (this->isProduceSchedulerSet()) { + if (!this->_producedOptimalChoices.is_initialized()) { + this->_producedOptimalChoices.emplace(); + } + this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount()); + } + + storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod(); + if (method == storm::solver::LraMethod::LinearProgramming) { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); + } else if (method == storm::solver::LraMethod::ValueIteration) { + return computeLraVi(env, stateRewardsGetter, actionRewardsGetter, component); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); + } } template - std::vector SparseNondeterministicGameInfiniteHorizonHelper::buildAndSolveSsp(Environment const& env, std::vector const& componentLraValues) { - STORM_LOG_THROW(false, storm::exceptions::InternalException, "buildAndSolveSsp not available for SMGs"); + ValueType SparseNondeterministicGameInfiniteHorizonHelper::computeLraVi(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) { + + // Collect some parameters of the computation + ValueType aperiodicFactor = storm::utility::convertNumber(env.solver().lra().getAperiodicFactor()); + std::vector* optimalChoices = nullptr; + if (this->isProduceSchedulerSet()) { + optimalChoices = &this->_producedOptimalChoices.get(); + } + + // Now create a helper and perform the algorithm + if (this->isContinuousTime()) { + STORM_LOG_THROW(false, storm::exceptions::InternalException, "We cannot handle continuous time games."); + } else { + storm::modelchecker::helper::internal::LraViHelper viHelper(mec, this->_transitionMatrix, aperiodicFactor); + return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices); + } } template - std::vector SparseNondeterministicGameInfiniteHorizonHelper::computeLongRunAverageValues(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter) { - STORM_LOG_THROW(false, storm::exceptions::InternalException, "computeLongRunAverageValues not possible yet."); + std::vector SparseNondeterministicGameInfiniteHorizonHelper::buildAndSolveSsp(Environment const& env, std::vector const& componentLraValues) { + STORM_LOG_THROW(false, storm::exceptions::InternalException, "We do not create compositions for LRA for SMGs, solving a stochastic shortest path problem is not available."); } diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h index fd872b807..f6075dc57 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h @@ -1,4 +1,5 @@ #pragma once + #include "storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h" namespace storm { @@ -29,31 +30,37 @@ namespace storm { */ SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, std::vector> const& player); - /*! - * TODO + /*! TODO + * 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 actionValuesGetter a function returning a value for a given (global) choice index + * @return a value for each state */ - std::vector computeLongRunAverageValues(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter); + std::vector computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) override; /*! * @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. */ - //std::vector const& getProducedOptimalChoices() const; + std::vector const& getProducedOptimalChoices() const; /*! * @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. */ - //std::vector& getProducedOptimalChoices(); + std::vector& getProducedOptimalChoices(); /*! * @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. */ - //storm::storage::Scheduler extractScheduler() const; + storm::storage::Scheduler extractScheduler() const; - void createDecomposition(); 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); + + void createDecomposition(); std::vector buildAndSolveSsp(Environment const& env, std::vector const& mecLraValues); private: From de385b0527798c5adc1168b39d5b5e7c3dcd119e Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 16:57:42 +0100 Subject: [PATCH 35/50] added method for lra game transition type also added the according template class constructions. --- .../helper/infinitehorizon/internal/LraViHelper.cpp | 9 ++++++++- .../helper/infinitehorizon/internal/LraViHelper.h | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index 2a4f6950a..101d21543 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -492,9 +492,16 @@ namespace storm { bool LraViHelper::nondetIs() const { return TransitionsType == LraViTransitionsType::DetTsNondetIs; } - + + template + bool LraViHelper::gameNondetTs() const { + return TransitionsType == LraViTransitionsType::GameNondetTsNoIs; + } + template class LraViHelper; template class LraViHelper; + template class LraViHelper; + template class LraViHelper; template class LraViHelper; template class LraViHelper; diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h index db1a30a01..c800a9976 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h @@ -128,7 +128,9 @@ namespace storm { /// @return true iff there potentially is a nondeterministic choice at instant states. Returns false if there are no instant states. bool nondetIs() const; - + /// @return true iff there potentially are nondeterministic choices for different players at timed states + bool gameNondetTs() const; + void setComponent(ComponentType component); // We need to make sure that states/choices will be processed in ascending order From c7d7be8b83f7083aa2c4d07b50e9059b275d9587 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 17:02:21 +0100 Subject: [PATCH 36/50] nondetTs may also be gameNondetTs in LraViHelper --- .../helper/infinitehorizon/internal/LraViHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index 101d21543..583468754 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -485,7 +485,7 @@ namespace storm { template bool LraViHelper::nondetTs() const { - return TransitionsType == LraViTransitionsType::NondetTsNoIs; + return TransitionsType == LraViTransitionsType::NondetTsNoIs || gameNondetTs(); } template From 505c830d42f89cedbb2696a209a9a4132aea61c9 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 17:05:05 +0100 Subject: [PATCH 37/50] set optdir overrides from multiplier env --- .../helper/infinitehorizon/internal/LraViHelper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index 583468754..97eb9a551 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -14,6 +14,7 @@ #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/LongRunAverageSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/exceptions/UnmetRequirementException.h" @@ -306,6 +307,9 @@ namespace storm { _TsToIsMultiplier = storm::solver::MultiplierFactory().create(env, _TsToIsTransitions); _IsToTsMultiplier = storm::solver::MultiplierFactory().create(env, _IsToTsTransitions); } + if(env.solver().multiplier().getOptimizationDirectionOverride().is_initialized()) { + _TsMultiplier->setOptimizationDirectionOverride(env.solver().multiplier().getOptimizationDirectionOverride().get()); + } } template From 50fdc36387ed4f7743ed2f0eed537e037c1e6e57 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 17:11:34 +0100 Subject: [PATCH 38/50] check convergence with weighted values This is used for approximations for LRA MC for SMGs. --- .../infinitehorizon/internal/LraViHelper.cpp | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index 97eb9a551..5e4bfc81a 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -173,7 +173,14 @@ namespace storm { while (!maxIter.is_initialized() || iter < maxIter.get()) { ++iter; performIterationStep(env, dir); - + + std::vector xOldTemp = xOld(); + std::vector xNewTemp = xNew(); + if(gameNondetTs() && iter > 1) { + // Weight values with current iteration step + storm::utility::vector::applyPointwise(xOld(), xOld(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)(iter - 1); }); + storm::utility::vector::applyPointwise(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; }); + } // Check if we are done auto convergenceCheckResult = checkConvergence(relative, precision); result = convergenceCheckResult.currentValue; @@ -183,6 +190,12 @@ namespace storm { if (storm::utility::resources::isTerminate()) { break; } + + if(gameNondetTs() && iter > 1) { + xOld() = xOldTemp; + xNew() = xNewTemp; + } + // If there will be a next iteration, we have to prepare it. prepareNextIteration(env); @@ -350,7 +363,7 @@ namespace storm { // The result of this ongoing computation will be stored in xNew() // Compute the values obtained by a single uniformization step between timed states only - if (nondetTs()) { + if (nondetTs() && !gameNondetTs()) { if (choices == nullptr) { _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew()); } else { @@ -362,6 +375,14 @@ namespace storm { STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states."); setInputModelChoices(*choices, tsChoices); } + } else if(gameNondetTs()) { // TODO DRYness? exact same behaviour as case above? + if (choices == nullptr) { + _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew()); + } else { + std::vector tsChoices(_TsTransitions.getRowGroupCount()); + _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices); + setInputModelChoices(*choices, tsChoices); // no components -> no need for that call? + } } else { _TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew()); } From 0e79f71435de222e677b07dc3b254adc58077c09 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 22 Dec 2020 17:38:56 +0100 Subject: [PATCH 39/50] change optimization direction if overridden --- src/storm/solver/GmmxxMultiplier.cpp | 30 ++++++++++++++++++---------- src/storm/solver/Multiplier.cpp | 6 ++++++ src/storm/solver/Multiplier.h | 5 +++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 6e0f727b0..15b1aefbd 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -1,5 +1,7 @@ #include "storm/solver/GmmxxMultiplier.h" +#include + #include "storm/adapters/RationalNumberAdapter.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/adapters/IntelTbbAdapter.h" @@ -166,23 +168,29 @@ namespace storm { choice_it = backwards ? choices->end() - 1 : choices->begin(); } + boost::optional optimizationDirectionOverride; + if(this->getOptimizationDirectionOverride().is_initialized()) { + optimizationDirectionOverride = this->getOptimizationDirectionOverride(); + } + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; uint64_t currentRow = backwards ? gmmMatrix.nrows() - 1 : 0; + uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 1 : 0; auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin(); auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1; while (row_group_it != row_group_ite) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if the row group is not empty. if (*row_group_it != *(row_group_it + 1)) { // Process the (backwards ? last : first) row of the current row group if (b) { currentValue = *add_it; } - + currentValue += vect_sp(gmm::linalg_traits::row(itr), x); if (choices) { @@ -202,18 +210,18 @@ namespace storm { ++currentRow; ++add_it; } - + // Process the (rowGroupSize-1) remaining rows within the current row Group uint64_t rowGroupSize = *(row_group_it + 1) - *row_group_it; for (uint64_t i = 1; i < rowGroupSize; ++i) { ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); - + if (choices && currentRow == *choice_it + *row_group_it) { oldSelectedChoiceValue = newValue; } - if (compare(newValue, currentValue)) { + if(isOverridden(currentRowGroup) ? !compare(newValue, currentValue) : compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; @@ -230,33 +238,35 @@ namespace storm { ++add_it; } } - + // Finally write value to target vector. *target_it = currentValue; - if (choices && compare(currentValue, oldSelectedChoiceValue)) { + if(choices && isOverridden(currentRowGroup) ? !compare(currentValue, oldSelectedChoiceValue) : compare(currentValue, oldSelectedChoiceValue) ) { *choice_it = selectedChoice; } } - + // move rowGroup-based iterators to the next row group if (backwards) { --row_group_it; --choice_it; --target_it; + --currentRowGroup; } else { ++row_group_it; ++choice_it; ++target_it; + ++currentRowGroup; } } } - + template<> template void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type."); } - + template void GmmxxMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 87e74b16a..556a4dfa9 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -84,6 +84,12 @@ namespace storm { return optimizationDirectionOverride; } + template + bool Multiplier::isOverridden(uint_fast64_t const index) const { + if(!optimizationDirectionOverride.is_initialized()) return false; + return optimizationDirectionOverride.get().get(index); + } + template std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { auto type = env.solver().multiplier().getType(); diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 552a427dd..acf754e94 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -147,6 +147,11 @@ namespace storm { */ boost::optional getOptimizationDirectionOverride() const; + /* + * TODO + */ + bool isOverridden(uint_fast64_t const index) const; + protected: mutable std::unique_ptr> cachedVector; storm::storage::SparseMatrix const& matrix; From b3f5cd1c89d7488073ad896bbbbb02077278dcca Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 23 Dec 2020 11:02:42 +0100 Subject: [PATCH 40/50] fixed call of inherited function and short curcuiting problem. Maybe && is overloaded somewhere? --- src/storm/solver/GmmxxMultiplier.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 15b1aefbd..32af42f72 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -221,7 +221,7 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if(isOverridden(currentRowGroup) ? !compare(newValue, currentValue) : compare(newValue, currentValue)) { + if(this->isOverridden(currentRowGroup) ? !compare(newValue, currentValue) : compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; @@ -241,8 +241,10 @@ namespace storm { // Finally write value to target vector. *target_it = currentValue; - if(choices && isOverridden(currentRowGroup) ? !compare(currentValue, oldSelectedChoiceValue) : compare(currentValue, oldSelectedChoiceValue) ) { - *choice_it = selectedChoice; + if(choices) { + if(this->isOverridden(currentRowGroup) ? !compare(currentValue, oldSelectedChoiceValue) : compare(currentValue, oldSelectedChoiceValue) ) { + *choice_it = selectedChoice; + } } } From e63faa485f68cadfd62575518e290d39a56685e3 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 19 Jan 2021 17:01:59 +0100 Subject: [PATCH 41/50] changed format of player parsing exceptions --- src/storm-parsers/parser/PrismParser.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm-parsers/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp index 23a3b3464..c77a56f2b 100644 --- a/src/storm-parsers/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -795,12 +795,12 @@ namespace storm { if (moduleIndexPair != globalProgramInformation.moduleToIndexMap.end()) { controlledModuleIndices.insert(std::pair(moduleIndexPair->first, moduleIndexPair->second)); if (std::find(globalProgramInformation.playerControlledModules.begin(), globalProgramInformation.playerControlledModules.end(), moduleName) != globalProgramInformation.playerControlledModules.end()) { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": Module '" << moduleName << "' already controlled by another player."); + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player '" << playerName << "': Module '" << moduleName << "' already controlled by another player."); } else { globalProgramInformation.playerControlledModules.push_back(moduleName); } } else { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": No module named '" << moduleName << "' present."); + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player '" << playerName << "': No module named '" << moduleName << "' present."); } } for(std::string actionName : actionNames) { @@ -808,12 +808,12 @@ namespace storm { if (actionIndexPair != globalProgramInformation.actionIndices.end()) { controlledActionIndices.insert(std::pair(actionIndexPair->first, actionIndexPair->second)); if (std::find(globalProgramInformation.playerControlledCommands.begin(), globalProgramInformation.playerControlledCommands.end(), actionName) != globalProgramInformation.playerControlledCommands.end()) { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": Command '" << actionName << "' already controlled by another player."); + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player '" << playerName << "': Command '" << actionName << "' already controlled by another player."); } else { globalProgramInformation.playerControlledCommands.push_back(actionName); } } else { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player " << playerName << ": No action named '" << actionName << "' present."); + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << " for player '" << playerName << "': No action named '" << actionName << "' present."); } } return storm::prism::Player(playerName, controlledModuleIndices, controlledActionIndices); From 432fef0a456b49369fcd81be18c4030a6081cbdf Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 19 Jan 2021 17:06:34 +0100 Subject: [PATCH 42/50] added GameMECDecomposition for testing purposes --- ...deterministicGameInfiniteHorizonHelper.cpp | 3 +- .../GameMaximalEndComponentDecomposition.cpp | 281 ++++++++++++++++++ .../GameMaximalEndComponentDecomposition.h | 109 +++++++ 3 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 src/storm/storage/GameMaximalEndComponentDecomposition.cpp create mode 100644 src/storm/storage/GameMaximalEndComponentDecomposition.h diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp index d48211af6..d4f52f65c 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp @@ -4,6 +4,7 @@ #include "storm/storage/SparseMatrix.h" #include "storm/storage/MaximalEndComponentDecomposition.h" +#include "storm/storage/GameMaximalEndComponentDecomposition.h" #include "storm/storage/Scheduler.h" #include "storm/solver/MinMaxLinearEquationSolver.h" @@ -61,7 +62,7 @@ namespace storm { this->_computedBackwardTransitions = std::make_unique>(this->_transitionMatrix.transpose(true)); this->_backwardTransitions = this->_computedBackwardTransitions.get(); } - this->_computedLongRunComponentDecomposition = std::make_unique>(this->_transitionMatrix, *this->_backwardTransitions); + this->_computedLongRunComponentDecomposition = std::make_unique>(this->_transitionMatrix, *this->_backwardTransitions); this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get(); } } diff --git a/src/storm/storage/GameMaximalEndComponentDecomposition.cpp b/src/storm/storage/GameMaximalEndComponentDecomposition.cpp new file mode 100644 index 000000000..f82933b6e --- /dev/null +++ b/src/storm/storage/GameMaximalEndComponentDecomposition.cpp @@ -0,0 +1,281 @@ +#include +#include +#include + +#include "storm/models/sparse/StandardRewardModel.h" + +#include "storm/storage/GameMaximalEndComponentDecomposition.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" + +namespace storm { + namespace storage { + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition() : Decomposition() { + // Intentionally left empty. + } + + template + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model) { + singleMEC(model.getTransitionMatrix(), model.getBackwardTransitions()); + //performGameMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions()); + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions) { + singleMEC(transitionMatrix, backwardTransitions); + //performGameMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions); + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& states) { + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices) { + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model, storm::storage::BitVector const& states) { + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other) : Decomposition(other) { + // Intentionally left empty. + } + + template + GameMaximalEndComponentDecomposition& GameMaximalEndComponentDecomposition::operator=(GameMaximalEndComponentDecomposition const& other) { + Decomposition::operator=(other); + return *this; + } + + template + GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other) : Decomposition(std::move(other)) { + // Intentionally left empty. + } + + template + GameMaximalEndComponentDecomposition& GameMaximalEndComponentDecomposition::operator=(GameMaximalEndComponentDecomposition&& other) { + Decomposition::operator=(std::move(other)); + return *this; + } + + template + void GameMaximalEndComponentDecomposition::performGameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) { + // Get some data for convenient access. + uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); + std::vector const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices(); + + // Initialize the maximal end component list to be the full state space. + std::list endComponentStateSets; + if (states) { + endComponentStateSets.emplace_back(states->begin(), states->end(), true); + } else { + std::vector allStates; + allStates.resize(transitionMatrix.getRowGroupCount()); + std::iota(allStates.begin(), allStates.end(), 0); + endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true); + } + storm::storage::BitVector statesToCheck(numberOfStates); + storm::storage::BitVector includedChoices; + if (choices) { + includedChoices = *choices; + } else if (states) { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount()); + for (auto state : *states) { + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + includedChoices.set(choice, true); + } + } + } else { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); + } + storm::storage::BitVector currMecAsBitVector(transitionMatrix.getRowGroupCount()); + + for (std::list::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) { + StateBlock const& mec = *mecIterator; + currMecAsBitVector.clear(); + currMecAsBitVector.set(mec.begin(), mec.end(), true); + // Keep track of whether the MEC changed during this iteration. + bool mecChanged = false; + + // Get an SCC decomposition of the current MEC candidate. + + StronglyConnectedComponentDecomposition sccs(transitionMatrix, StronglyConnectedComponentDecompositionOptions().subsystem(&currMecAsBitVector).choices(&includedChoices).dropNaiveSccs()); + for(auto const& sc: sccs) { + STORM_LOG_DEBUG("SCC size: " << sc.size()); + } + + // We need to do another iteration in case we have either more than once SCC or the SCC is smaller than + // the MEC canditate itself. + mecChanged |= sccs.size() != 1 || (sccs.size() > 0 && sccs[0].size() < mec.size()); + + // Check for each of the SCCs whether all actions for each state do not leave the SCC. // TODO there is certainly a better way to do that... + for (auto& scc : sccs) { + statesToCheck.set(scc.begin(), scc.end()); + + while (!statesToCheck.empty()) { + storm::storage::BitVector statesToRemove(numberOfStates); + + for (auto state : statesToCheck) { + bool keepStateInMEC = true; + + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + + // If the choice is not part of our subsystem, skip it. + if (choices && !choices->get(choice)) { + continue; + } + + // If the choice is not included any more, skip it. + //if (!includedChoices.get(choice)) { + // continue; + //} + + bool choiceContainedInMEC = true; + for (auto const& entry : transitionMatrix.getRow(choice)) { + if (storm::utility::isZero(entry.getValue())) { + continue; + } + + if (!scc.containsState(entry.getColumn())) { + //includedChoices.set(choice, false); + choiceContainedInMEC = false; + break; + } + } + + //TODO If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC. + if (!choiceContainedInMEC) { + keepStateInMEC = false; + break; + } + } + if (!keepStateInMEC) { + statesToRemove.set(state, true); + } + + } + + // Now erase the states that have no option to stay inside the MEC with all successors. + mecChanged |= !statesToRemove.empty(); + for (uint_fast64_t state : statesToRemove) { + scc.erase(state); + } + + // Now check which states should be reconsidered, because successors of them were removed. + statesToCheck.clear(); + for (auto state : statesToRemove) { + for (auto const& entry : backwardTransitions.getRow(state)) { + if (scc.containsState(entry.getColumn())) { + statesToCheck.set(entry.getColumn()); + } + } + } + } + } + + // If the MEC changed, we delete it from the list of MECs and append the possible new MEC candidates to + // the list instead. + if (mecChanged) { + for (StronglyConnectedComponent& scc : sccs) { + if (!scc.empty()) { + endComponentStateSets.push_back(std::move(scc)); + } + } + + std::list::const_iterator eraseIterator(mecIterator); + ++mecIterator; + endComponentStateSets.erase(eraseIterator); + } else { + // Otherwise, we proceed with the next MEC candidate. + ++mecIterator; + } + + } // End of loop over all MEC candidates. + + // Now that we computed the underlying state sets of the MECs, we need to properly identify the choices + // contained in the MEC and store them as actual MECs. + this->blocks.reserve(endComponentStateSets.size()); + for (auto const& mecStateSet : endComponentStateSets) { + MaximalEndComponent newMec; + + for (auto state : mecStateSet) { + MaximalEndComponent::set_type containedChoices; + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + // Skip the choice if it is not part of our subsystem. + if (choices && !choices->get(choice)) { + continue; + } + + if (includedChoices.get(choice)) { + containedChoices.insert(choice); + } + } + + STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty."); + newMec.addState(state, std::move(containedChoices)); + } + + this->blocks.emplace_back(std::move(newMec)); + } + + STORM_LOG_DEBUG("MEC decomposition found " << this->size() << " GMEC(s)."); + } + + template + void GameMaximalEndComponentDecomposition::singleMEC(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) { + MaximalEndComponent singleMec; + + std::vector const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices(); + + std::list endComponentStateSets; + std::vector allStates; + allStates.resize(transitionMatrix.getRowGroupCount()); + std::iota(allStates.begin(), allStates.end(), 0); + endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true); + + storm::storage::BitVector includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); + this->blocks.reserve(endComponentStateSets.size()); + for (auto const& mecStateSet : endComponentStateSets) { + MaximalEndComponent newMec; + + for (auto state : mecStateSet) { + MaximalEndComponent::set_type containedChoices; + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + // Skip the choice if it is not part of our subsystem. + if (choices && !choices->get(choice)) { + continue; + } + + if (includedChoices.get(choice)) { + containedChoices.insert(choice); + } + } + + STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty."); + newMec.addState(state, std::move(containedChoices)); + } + + this->blocks.emplace_back(std::move(newMec)); + } + + STORM_LOG_DEBUG("Whole state space is one single MEC"); + + } + + // Explicitly instantiate the MEC decomposition. + template class GameMaximalEndComponentDecomposition; + template GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model); + +#ifdef STORM_HAVE_CARL + template class GameMaximalEndComponentDecomposition; + template GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model); + + template class GameMaximalEndComponentDecomposition; + template GameMaximalEndComponentDecomposition::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model); +#endif + } +} diff --git a/src/storm/storage/GameMaximalEndComponentDecomposition.h b/src/storm/storage/GameMaximalEndComponentDecomposition.h new file mode 100644 index 000000000..36c590426 --- /dev/null +++ b/src/storm/storage/GameMaximalEndComponentDecomposition.h @@ -0,0 +1,109 @@ +#ifndef STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ +#define STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ + +#include "storm/storage/Decomposition.h" +#include "storm/storage/MaximalEndComponent.h" +#include "storm/models/sparse/NondeterministicModel.h" + +namespace storm { + namespace storage { + + /*! + * This class represents the decomposition of a stochastic multiplayer game into its (irreducible) maximal end components. + */ + template + class GameMaximalEndComponentDecomposition : public Decomposition { + public: + /* + * Creates an empty MEC decomposition. + */ + GameMaximalEndComponentDecomposition(); + + /* + * Creates an MEC decomposition of the given model. + * + * @param model The model to decompose into MECs. + */ + template > + GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model); + + /* + * Creates an MEC decomposition of the given model (represented by a row-grouped matrix). + * + * @param transitionMatrix The transition relation of model to decompose into MECs. + * @param backwardTransition The reversed transition relation. + */ + GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions); + + /* + * Creates an MEC decomposition of the given subsystem of given model (represented by a row-grouped matrix). + * + * @param transitionMatrix The transition relation of model to decompose into MECs. + * @param backwardTransition The reversed transition relation. + * @param states The states of the subsystem to decompose. + */ + GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& states); + + /* + * Creates an MEC decomposition of the given subsystem of given model (represented by a row-grouped matrix). + * + * @param transitionMatrix The transition relation of model to decompose into MECs. + * @param backwardTransition The reversed transition relation. + * @param states The states of the subsystem to decompose. + * @param choices The choices of the subsystem to decompose. + */ + GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices); + + /*! + * Creates an MEC decomposition of the given subsystem in the given model. + * + * @param model The model whose subsystem to decompose into MECs. + * @param states The states of the subsystem to decompose. + */ + GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel const& model, storm::storage::BitVector const& states); + + /*! + * Creates an MEC decomposition by copying the contents of the given MEC decomposition. + * + * @param other The MEC decomposition to copy. + */ + GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other); + + /*! + * Assigns the contents of the given MEC decomposition to the current one by copying its contents. + * + * @param other The MEC decomposition from which to copy-assign. + */ + GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition const& other); + + /*! + * Creates an MEC decomposition by moving the contents of the given MEC decomposition. + * + * @param other The MEC decomposition to move. + */ + GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other); + + /*! + * Assigns the contents of the given MEC decomposition to the current one by moving its contents. + * + * @param other The MEC decomposition from which to move-assign. + */ + GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition&& other); + + private: + /*! + * Performs the actual decomposition of the given subsystem in the given model into MECs. As a side-effect + * this stores the MECs found in the current decomposition. + * + * @param transitionMatrix The transition matrix representing the system whose subsystem to decompose into MECs. + * @param backwardTransitions The reversed transition relation. + * @param states The states of the subsystem to decompose. + * @param choices The choices of the subsystem to decompose. + */ + void performGameMaximalEndComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr); + void singleMEC(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr); + }; + } +} + +#endif /* STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ */ From c6c5c5cc13a040a96003e3ae66639aa41854e425 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 19 Jan 2021 17:16:37 +0100 Subject: [PATCH 43/50] smg lra debug commit this should be dropped in the future --- src/storm/builder/ExplicitModelBuilder.cpp | 1 + ...deterministicGameInfiniteHorizonHelper.cpp | 3 + .../infinitehorizon/internal/LraViHelper.cpp | 71 ++- .../rpatl/SparseSmgRpatlModelChecker.cpp | 4 + src/storm/solver/GmmxxMultiplier.cpp | 77 ++- src/storm/storage/Decomposition.cpp | 56 +- src/storm/storage/MaximalEndComponent.cpp | 66 +- src/storm/storage/SparseMatrix.cpp | 593 +++++++++--------- 8 files changed, 447 insertions(+), 424 deletions(-) diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp index 3e224a419..dadbe9a8c 100644 --- a/src/storm/builder/ExplicitModelBuilder.cpp +++ b/src/storm/builder/ExplicitModelBuilder.cpp @@ -161,6 +161,7 @@ namespace storm { while (!statesToExplore.empty()) { // Get the first state in the queue. CompressedState currentState = statesToExplore.front().first; + STORM_LOG_DEBUG("Exploring (" << currentRowGroup << ") : " << toString(currentState, this->generator->getVariableInformation())); StateType currentIndex = statesToExplore.front().second; statesToExplore.pop_front(); diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp index d4f52f65c..34a1a8d93 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp @@ -63,7 +63,10 @@ namespace storm { this->_backwardTransitions = this->_computedBackwardTransitions.get(); } this->_computedLongRunComponentDecomposition = std::make_unique>(this->_transitionMatrix, *this->_backwardTransitions); + this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get(); + //STORM_LOG_DEBUG("\n" << this->_transitionMatrix); + STORM_LOG_DEBUG("GMEC: " << *(this->_longRunComponentDecomposition)); } } diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index 5e4bfc81a..da16522f1 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -24,11 +24,11 @@ namespace storm { namespace modelchecker { namespace helper { namespace internal { - + template LraViHelper::LraViHelper(ComponentType const& component, storm::storage::SparseMatrix const& transitionMatrix, ValueType const& aperiodicFactor, storm::storage::BitVector const* timedStates, std::vector const* exitRates) : _transitionMatrix(transitionMatrix), _timedStates(timedStates), _hasInstantStates(TransitionsType == LraViTransitionsType::DetTsNondetIs || TransitionsType == LraViTransitionsType::DetTsDetIs), _Tsx1IsCurrent(false) { setComponent(component); - + // Run through the component and collect some data: // We create two submodels, one consisting of the timed states of the component and one consisting of the instant states of the component. // For this, we create a state index map that point from state indices of the input model to indices of the corresponding submodel of that state. @@ -141,8 +141,9 @@ namespace storm { _IsTransitions = isTransitionsBuilder.build(); _IsToTsTransitions = isToTsTransitionsBuilder.build(); } + STORM_LOG_DEBUG(uniformizationFactor << " - " << _uniformizationRate); } - + template void LraViHelper::setComponent(ComponentType component) { _component.clear(); @@ -156,7 +157,7 @@ namespace storm { } } - + template ValueType LraViHelper::performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector const* exitRates, storm::solver::OptimizationDirection const* dir, std::vector* choices) { initializeNewValues(stateValueGetter, actionValueGetter, exitRates); @@ -166,7 +167,7 @@ namespace storm { if (env.solver().lra().isMaximalIterationCountSet()) { maxIter = env.solver().lra().getMaximalIterationCount(); } - + // start the iterations ValueType result = storm::utility::zero(); uint64_t iter = 0; @@ -198,7 +199,7 @@ namespace storm { // If there will be a next iteration, we have to prepare it. prepareNextIteration(env); - + } if (maxIter.is_initialized() && iter == maxIter.get()) { STORM_LOG_WARN("LRA computation did not converge within " << iter << " iterations."); @@ -207,15 +208,23 @@ namespace storm { } else { STORM_LOG_TRACE("LRA computation converged after " << iter << " iterations."); } - + if (choices) { // We will be doing one more iteration step and track scheduler choices this time. prepareNextIteration(env); performIterationStep(env, dir, choices); } + std::cout << "result (" << iter << " steps):" << std::endl; + for(int i = 0; i < xNew().size() ; i++ ) { + std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl; + //if(i == 50) {std::cout << "only showing top 50 lines"; break; } + for(int i = 0; i < xNew().size() ; i++ ) { + std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl; + //if(i == 50) {std::cout << "only showing top 50 lines"; break; } + } return result; } - + template void LraViHelper::initializeNewValues(ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector const* exitRates) { // clear potential old values and reserve enough space for new values @@ -225,7 +234,7 @@ namespace storm { _IsChoiceValues.clear(); _IsChoiceValues.reserve(_IsTransitions.getRowCount()); } - + // Set the new choice-based values ValueType actionRewardScalingFactor = storm::utility::one() / _uniformizationRate; for (auto const& element : _component) { @@ -250,14 +259,14 @@ namespace storm { // Set-up new iteration vectors for timed states _Tsx1.assign(_TsTransitions.getRowGroupCount(), storm::utility::zero()); _Tsx2 = _Tsx1; - + if (_hasInstantStates) { // Set-up vectors for storing intermediate results for instant states. _Isx.resize(_IsTransitions.getRowGroupCount(), storm::utility::zero()); _Isb = _IsChoiceValues; } } - + template void LraViHelper::prepareSolversAndMultipliers(const Environment& env, storm::solver::OptimizationDirection const* dir) { _TsMultiplier = storm::solver::MultiplierFactory().create(env, _TsTransitions); @@ -315,7 +324,7 @@ namespace storm { STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException, "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been cleared."); } } - + // Set up multipliers for transitions connecting timed and instant states _TsToIsMultiplier = storm::solver::MultiplierFactory().create(env, _TsToIsTransitions); _IsToTsMultiplier = storm::solver::MultiplierFactory().create(env, _IsToTsTransitions); @@ -324,7 +333,7 @@ namespace storm { _TsMultiplier->setOptimizationDirectionOverride(env.solver().multiplier().getOptimizationDirectionOverride().get()); } } - + template void LraViHelper::setInputModelChoices(std::vector& choices, std::vector const& localMecChoices, bool setChoiceZeroToTimedStates, bool setChoiceZeroToInstantStates) const { // Transform the local choices (within this mec) to choice indices for the input model @@ -347,7 +356,7 @@ namespace storm { } STORM_LOG_ASSERT(localState == localMecChoices.size(), "Did not traverse all component states."); } - + template void LraViHelper::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir, std::vector* choices) { STORM_LOG_ASSERT(!((nondetTs() || nondetIs()) && dir == nullptr), "No optimization direction provided for model with nondeterminism"); @@ -355,13 +364,13 @@ namespace storm { if (!_TsMultiplier) { prepareSolversAndMultipliers(env, dir); } - + // Compute new x values for the timed states // Flip what is new and what is old _Tsx1IsCurrent = !_Tsx1IsCurrent; // At this point, xOld() points to what has been computed in the most recent call of performIterationStep (initially, this is the 0-vector). // The result of this ongoing computation will be stored in xNew() - + // Compute the values obtained by a single uniformization step between timed states only if (nondetTs() && !gameNondetTs()) { if (choices == nullptr) { @@ -425,7 +434,7 @@ namespace storm { _TsToIsMultiplier->multiply(env, _Isx, &xNew(), xNew()); } } - + template typename LraViHelper::ConvergenceCheckResult LraViHelper::checkConvergence(bool relative, ValueType precision) const { STORM_LOG_ASSERT(_TsMultiplier, "tried to check for convergence without doing an iteration first."); @@ -433,7 +442,7 @@ namespace storm { // We need to 'revert' this scaling when computing the absolute precision. // However, for relative precision, the scaling cancels out. ValueType threshold = relative ? precision : ValueType(precision / _uniformizationRate); - + ConvergenceCheckResult res = { true, storm::utility::one() }; // Now check whether the currently produced results are precise enough STORM_LOG_ASSERT(threshold > storm::utility::zero(), "Did not expect a non-positive threshold."); @@ -460,15 +469,15 @@ namespace storm { break; } } - + // Compute the average of the maximal and the minimal difference. ValueType avgDiff = (maxDiff + minDiff) / (storm::utility::convertNumber(2.0)); - + // "Undo" the scaling of the values res.currentValue = avgDiff * _uniformizationRate; return res; } - + template void LraViHelper::prepareNextIteration(Environment const& env) { // To avoid large (and numerically unstable) x-values, we substract a reference value. @@ -480,39 +489,39 @@ namespace storm { _IsToTsMultiplier->multiply(env, xNew(), &_IsChoiceValues, _Isb); } } - + template bool LraViHelper::isTimedState(uint64_t const& inputModelStateIndex) const { STORM_LOG_ASSERT(!_hasInstantStates || _timedStates != nullptr, "Model has instant states but no partition into timed and instant states is given."); STORM_LOG_ASSERT(!_hasInstantStates || inputModelStateIndex < _timedStates->size(), "Unable to determine whether state " << inputModelStateIndex << " is timed."); return !_hasInstantStates || _timedStates->get(inputModelStateIndex); } - + template std::vector& LraViHelper::xNew() { return _Tsx1IsCurrent ? _Tsx1 : _Tsx2; } - + template std::vector const& LraViHelper::xNew() const { return _Tsx1IsCurrent ? _Tsx1 : _Tsx2; } - + template std::vector& LraViHelper::xOld() { return _Tsx1IsCurrent ? _Tsx2 : _Tsx1; } - + template std::vector const& LraViHelper::xOld() const { return _Tsx1IsCurrent ? _Tsx2 : _Tsx1; } - + template bool LraViHelper::nondetTs() const { return TransitionsType == LraViTransitionsType::NondetTsNoIs || gameNondetTs(); } - + template bool LraViHelper::nondetIs() const { return TransitionsType == LraViTransitionsType::DetTsNondetIs; @@ -529,11 +538,11 @@ namespace storm { template class LraViHelper; template class LraViHelper; template class LraViHelper; - + template class LraViHelper; template class LraViHelper; - + } } } -} \ No newline at end of file +} diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp index 3b217030e..b8d4b64a6 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -65,6 +65,7 @@ namespace storm { Environment solverEnv = env; coalitionIndicator(solverEnv, checkTask); + storm::logic::GameFormula const& gameFormula = checkTask.getFormula(); storm::logic::Formula const& subFormula = gameFormula.getSubformula(); @@ -143,6 +144,8 @@ namespace storm { playerIds.push_back(boost::get(player) - 1); } } + //for(auto const& p : playerActionIndices) std::cout << p.first << " - " << p.second << ", "; std::cout << std::endl; + //for(auto const& p : playerIds) std::cout << p << ", "; std::cout << std::endl; for(uint i = 0; i < playerActionIndices.size(); i++) { if(std::find(playerIds.begin(), playerIds.end(), playerActionIndices.at(i).second) != playerIds.end()) { @@ -151,6 +154,7 @@ namespace storm { } coalitionIndicators.complement(); + //std::cout << "MINMAX OVERRIDE: " << coalitionIndicators << std::endl; env.solver().multiplier().setOptimizationDirectionOverride(coalitionIndicators); } diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 32af42f72..0a2843824 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -16,25 +16,26 @@ namespace storm { namespace solver { - + template GmmxxMultiplier::GmmxxMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. + //STORM_LOG_DEBUG("\n" << matrix); } - + template void GmmxxMultiplier::initialize() const { if (gmmMatrix.nrows() == 0) { gmmMatrix = std::move(*storm::adapters::GmmxxAdapter().toGmmxxSparseMatrix(this->matrix)); } } - + template void GmmxxMultiplier::clearCache() const { gmmMatrix = gmm::csr_matrix(); Multiplier::clearCache(); } - + template bool GmmxxMultiplier::parallelize(Environment const& env) const { #ifdef STORM_HAVE_INTELTBB @@ -43,7 +44,7 @@ namespace storm { return false; #endif } - + template void GmmxxMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { initialize(); @@ -65,7 +66,7 @@ namespace storm { std::swap(result, *this->cachedVector); } } - + template void GmmxxMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b, bool backwards) const { initialize(); @@ -84,7 +85,7 @@ namespace storm { } } } - + template void GmmxxMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { initialize(); @@ -106,13 +107,13 @@ namespace storm { std::swap(result, *this->cachedVector); } } - + template void GmmxxMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices, bool backwards) const { initialize(); multAddReduceHelper(dir, rowGroupIndices, x, b, x, choices, backwards); } - + template void GmmxxMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { initialize(); @@ -148,14 +149,14 @@ namespace storm { } } } - + template template void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { Compare compare; typedef std::vector VectorType; typedef gmm::csr_matrix MatrixType; - + typename gmm::linalg_traits::const_iterator add_it, add_ite; if (b) { add_it = backwards ? gmm::vect_end(*b) - 1 : gmm::vect_begin(*b); @@ -181,6 +182,7 @@ namespace storm { uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 1 : 0; auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin(); auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1; + //if(choices) STORM_LOG_DEBUG(" "); while (row_group_it != row_group_ite) { ValueType currentValue = storm::utility::zero(); @@ -199,7 +201,7 @@ namespace storm { oldSelectedChoiceValue = currentValue; } } - + // move row-based iterators to the next row if (backwards) { --itr; @@ -213,6 +215,10 @@ namespace storm { // Process the (rowGroupSize-1) remaining rows within the current row Group uint64_t rowGroupSize = *(row_group_it + 1) - *row_group_it; + uint choiceforprintout = 0; + //std::cout << currentRowGroup << ": " << currentValue << ", "; + //STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits::row(itr), x) << " + " << *add_it << "; "); + //STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits::row(itr), x) << " + " << *add_it << "; "); for (uint64_t i = 1; i < rowGroupSize; ++i) { ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); @@ -220,12 +226,13 @@ namespace storm { if (choices && currentRow == *choice_it + *row_group_it) { oldSelectedChoiceValue = newValue; } - - if(this->isOverridden(currentRowGroup) ? !compare(newValue, currentValue) : compare(newValue, currentValue)) { + //std::cout << newValue << ", "; + //STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits::row(itr), x) << " + " << *add_it << "; "); currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; } + choiceforprintout = currentRow - *row_group_it; } // move row-based iterators to the next row if (backwards) { @@ -238,7 +245,8 @@ namespace storm { ++add_it; } } - + //STORM_LOG_DEBUG("\t= " << currentValue << "\tchoice: " << choiceforprintout); + //std::cout << std::fixed << std::setprecision(2) << " | v(" << currentRowGroup << ")=" << currentValue << " c: " << choiceforprintout << " |\n" ; // Finally write value to target vector. *target_it = currentValue; if(choices) { @@ -261,6 +269,7 @@ namespace storm { ++currentRowGroup; } } + //std::cout << std::endl; } template<> @@ -286,7 +295,7 @@ namespace storm { multAdd(x, b, result); #endif } - + #ifdef STORM_HAVE_INTELTBB template class TbbMultAddReduceFunctor { @@ -294,14 +303,14 @@ namespace storm { TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { // Intentionally left empty. } - + void operator()(tbb::blocked_range const& range) const { typedef std::vector VectorType; typedef gmm::csr_matrix MatrixType; auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); - + auto itr = mat_row_const_begin(matrix) + *groupIt; typename std::vector::const_iterator bIt; if (b) { @@ -311,40 +320,40 @@ namespace storm { if (choices) { choiceIt = choices->begin() + range.begin(); } - + auto resultIt = result.begin() + range.begin(); - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; - + uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if the row group is not empty. if (*groupIt != *(groupIt + 1)) { if (b) { currentValue = *bIt; ++bIt; } - + currentValue += vect_sp(gmm::linalg_traits::row(itr), x); - + if (choices) { selectedChoice = currentRow - *groupIt; if (*choiceIt == selectedChoice) { oldSelectedChoiceValue = currentValue; } } - + ++itr; ++currentRow; - + for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr, ++bIt, ++currentRow) { ValueType newValue = b ? *bIt : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); - + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { @@ -353,7 +362,7 @@ namespace storm { } } } - + // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { @@ -361,7 +370,7 @@ namespace storm { } } } - + private: Compare compare; std::vector const& rowGroupIndices; @@ -372,7 +381,7 @@ namespace storm { std::vector* choices; }; #endif - + template void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB @@ -386,18 +395,18 @@ namespace storm { multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices); #endif } - + template<> void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } - + template class GmmxxMultiplier; - + #ifdef STORM_HAVE_CARL template class GmmxxMultiplier; template class GmmxxMultiplier; #endif - + } } diff --git a/src/storm/storage/Decomposition.cpp b/src/storm/storage/Decomposition.cpp index efe850083..a45987d69 100644 --- a/src/storm/storage/Decomposition.cpp +++ b/src/storm/storage/Decomposition.cpp @@ -8,84 +8,84 @@ namespace storm { namespace storage { - + template Decomposition::Decomposition() : blocks() { // Intentionally left empty. } - + template Decomposition::Decomposition(Decomposition const& other) : blocks(other.blocks) { // Intentionally left empty. } - + template Decomposition& Decomposition::operator=(Decomposition const& other) { this->blocks = other.blocks; return *this; } - + template Decomposition::Decomposition(Decomposition&& other) : blocks(std::move(other.blocks)) { // Intentionally left empty. } - + template Decomposition& Decomposition::operator=(Decomposition&& other) { this->blocks = std::move(other.blocks); return *this; } - + template std::size_t Decomposition::size() const { return blocks.size(); } - + template bool Decomposition::empty() const { return blocks.empty(); } - + template typename Decomposition::iterator Decomposition::begin() { return blocks.begin(); } - + template typename Decomposition::iterator Decomposition::end() { return blocks.end(); } - + template typename Decomposition::const_iterator Decomposition::begin() const { return blocks.begin(); } - + template typename Decomposition::const_iterator Decomposition::end() const { return blocks.end(); } - + template BlockType const& Decomposition::getBlock(uint_fast64_t index) const { return blocks.at(index); } - + template BlockType& Decomposition::getBlock(uint_fast64_t index) { return blocks.at(index); } - + template BlockType const& Decomposition::operator[](uint_fast64_t index) const { return blocks[index]; } - + template BlockType& Decomposition::operator[](uint_fast64_t index) { return blocks[index]; } - + template template storm::storage::SparseMatrix Decomposition::extractPartitionDependencyGraph(storm::storage::SparseMatrix const& matrix) const { @@ -97,49 +97,49 @@ namespace storm { stateToBlockMap[state] = i; } } - + // The resulting sparse matrix will have as many rows/columns as there are blocks in the partition. storm::storage::SparseMatrixBuilder dependencyGraphBuilder(this->size(), this->size()); - + for (uint_fast64_t currentBlockIndex = 0; currentBlockIndex < this->size(); ++currentBlockIndex) { // Get the next block. block_type const& block = this->getBlock(currentBlockIndex); - + // Now, we determine the blocks which are reachable (in one step) from the current block. storm::storage::FlatSet allTargetBlocks; for (auto state : block) { for (auto const& transitionEntry : matrix.getRowGroup(state)) { uint_fast64_t targetBlock = stateToBlockMap[transitionEntry.getColumn()]; - + // We only need to consider transitions that are actually leaving the SCC. if (targetBlock != currentBlockIndex) { allTargetBlocks.insert(targetBlock); } } } - + // Now we can just enumerate all the target blocks and insert the corresponding transitions. for (auto const& targetBlock : allTargetBlocks) { dependencyGraphBuilder.addNextValue(currentBlockIndex, targetBlock, storm::utility::one()); } } - + return dependencyGraphBuilder.build(); } - + template std::ostream& operator<<(std::ostream& out, Decomposition const& decomposition) { - out << "["; + out << "[ "; if (decomposition.size() > 0) { for (uint_fast64_t blockIndex = 0; blockIndex < decomposition.size() - 1; ++blockIndex) { - out << decomposition.blocks[blockIndex] << ", "; + out << decomposition.blocks[blockIndex] << ", " << std::endl; } out << decomposition.blocks.back(); } - out << "]"; + out << " ]"; return out; } - + template storm::storage::SparseMatrix Decomposition::extractPartitionDependencyGraph(storm::storage::SparseMatrix const& matrix) const; template storm::storage::SparseMatrix Decomposition::extractPartitionDependencyGraph(storm::storage::SparseMatrix const& matrix) const; template class Decomposition; @@ -149,7 +149,7 @@ namespace storm { template storm::storage::SparseMatrix Decomposition::extractPartitionDependencyGraph(storm::storage::SparseMatrix const& matrix) const; template class Decomposition; template std::ostream& operator<<(std::ostream& out, Decomposition const& decomposition); - + template class Decomposition; template std::ostream& operator<<(std::ostream& out, Decomposition const& decomposition); } // namespace storage diff --git a/src/storm/storage/MaximalEndComponent.cpp b/src/storm/storage/MaximalEndComponent.cpp index 68e8eda99..58683a3df 100644 --- a/src/storm/storage/MaximalEndComponent.cpp +++ b/src/storm/storage/MaximalEndComponent.cpp @@ -3,125 +3,125 @@ namespace storm { namespace storage { - + std::ostream& operator<<(std::ostream& out, storm::storage::FlatSet const& block); - + MaximalEndComponent::MaximalEndComponent() : stateToChoicesMapping() { // Intentionally left empty. } - + MaximalEndComponent::MaximalEndComponent(MaximalEndComponent const& other) : stateToChoicesMapping(other.stateToChoicesMapping) { // Intentionally left empty. } - + MaximalEndComponent& MaximalEndComponent::operator=(MaximalEndComponent const& other) { stateToChoicesMapping = other.stateToChoicesMapping; return *this; } - + MaximalEndComponent::MaximalEndComponent(MaximalEndComponent&& other) : stateToChoicesMapping(std::move(other.stateToChoicesMapping)) { // Intentionally left empty. } - + MaximalEndComponent& MaximalEndComponent::operator=(MaximalEndComponent&& other) { stateToChoicesMapping = std::move(other.stateToChoicesMapping); return *this; } - + void MaximalEndComponent::addState(uint_fast64_t state, set_type const& choices) { stateToChoicesMapping[state] = choices; } - + void MaximalEndComponent::addState(uint_fast64_t state, set_type&& choices) { stateToChoicesMapping.emplace(state, std::move(choices)); } - + std::size_t MaximalEndComponent::size() const { return stateToChoicesMapping.size(); } - + MaximalEndComponent::set_type const& MaximalEndComponent::getChoicesForState(uint_fast64_t state) const { auto stateChoicePair = stateToChoicesMapping.find(state); - + if (stateChoicePair == stateToChoicesMapping.end()) { throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::getChoicesForState: cannot retrieve choices for state not contained in MEC."; } - + return stateChoicePair->second; } - + MaximalEndComponent::set_type& MaximalEndComponent::getChoicesForState(uint_fast64_t state) { auto stateChoicePair = stateToChoicesMapping.find(state); - + if (stateChoicePair == stateToChoicesMapping.end()) { throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::getChoicesForState: cannot retrieve choices for state not contained in MEC."; } - + return stateChoicePair->second; } - + bool MaximalEndComponent::containsState(uint_fast64_t state) const { auto stateChoicePair = stateToChoicesMapping.find(state); - + if (stateChoicePair == stateToChoicesMapping.end()) { return false; } return true; } - + void MaximalEndComponent::removeState(uint_fast64_t state) { auto stateChoicePair = stateToChoicesMapping.find(state); - + if (stateChoicePair == stateToChoicesMapping.end()) { throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::removeState: cannot remove state not contained in MEC."; } - + stateToChoicesMapping.erase(stateChoicePair); } - + bool MaximalEndComponent::containsChoice(uint_fast64_t state, uint_fast64_t choice) const { auto stateChoicePair = stateToChoicesMapping.find(state); - + if (stateChoicePair == stateToChoicesMapping.end()) { throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::containsChoice: cannot obtain choices for state not contained in MEC."; } - + return stateChoicePair->second.find(choice) != stateChoicePair->second.end(); } - + MaximalEndComponent::set_type MaximalEndComponent::getStateSet() const { set_type states; states.reserve(stateToChoicesMapping.size()); - + for (auto const& stateChoicesPair : stateToChoicesMapping) { states.insert(stateChoicesPair.first); } - + return states; } - + std::ostream& operator<<(std::ostream& out, MaximalEndComponent const& component) { out << "{"; for (auto const& stateChoicesPair : component.stateToChoicesMapping) { - out << "{" << stateChoicesPair.first << ", " << stateChoicesPair.second << "}"; + out << "(" << stateChoicesPair.first << ", " << stateChoicesPair.second << ")"; } out << "}"; - + return out; } - + MaximalEndComponent::iterator MaximalEndComponent::begin() { return stateToChoicesMapping.begin(); } - + MaximalEndComponent::iterator MaximalEndComponent::end() { return stateToChoicesMapping.end(); } - + MaximalEndComponent::const_iterator MaximalEndComponent::begin() const { return stateToChoicesMapping.begin(); } - + MaximalEndComponent::const_iterator MaximalEndComponent::end() const { return stateToChoicesMapping.end(); } diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 05a526702..d89f7a568 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -21,64 +21,64 @@ namespace storm { namespace storage { - + template MatrixEntry::MatrixEntry(IndexType column, ValueType value) : entry(column, value) { // Intentionally left empty. } - + template MatrixEntry::MatrixEntry(std::pair&& pair) : entry(std::move(pair)) { // Intentionally left empty. } - + template IndexType const& MatrixEntry::getColumn() const { return this->entry.first; } - + template void MatrixEntry::setColumn(IndexType const& column) { this->entry.first = column; } - + template ValueType const& MatrixEntry::getValue() const { return this->entry.second; } - + template void MatrixEntry::setValue(ValueType const& value) { this->entry.second = value; } - + template std::pair const& MatrixEntry::getColumnValuePair() const { return this->entry; } - + template MatrixEntry MatrixEntry::operator*(value_type factor) const { return MatrixEntry(this->getColumn(), this->getValue() * factor); } - - + + template bool MatrixEntry::operator==(MatrixEntry const& other) const { return this->entry.first == other.entry.first && this->entry.second == other.entry.second; } - + template bool MatrixEntry::operator!=(MatrixEntry const& other) const { return !(*this == other); } - + template std::ostream& operator<<(std::ostream& out, MatrixEntry const& entry) { out << "(" << entry.getColumn() << ", " << entry.getValue() << ")"; return out; } - + template SparseMatrixBuilder::SparseMatrixBuilder(index_type rows, index_type columns, index_type entries, bool forceDimensions, bool hasCustomRowGrouping, index_type rowGroups) : initialRowCountSet(rows != 0), initialRowCount(rows), initialColumnCountSet(columns != 0), initialColumnCount(columns), initialEntryCountSet(entries != 0), initialEntryCount(entries), forceInitialDimensions(forceDimensions), hasCustomRowGrouping(hasCustomRowGrouping), initialRowGroupCountSet(rowGroups != 0), initialRowGroupCount(rowGroups), rowGroupIndices(), columnsAndValues(), rowIndications(), currentEntryCount(0), lastRow(0), lastColumn(0), highestColumn(0), currentRowGroupCount(0) { // Prepare the internal storage. @@ -96,14 +96,14 @@ namespace storm { } rowIndications.push_back(0); } - + template SparseMatrixBuilder::SparseMatrixBuilder(SparseMatrix&& matrix) : initialRowCountSet(false), initialRowCount(0), initialColumnCountSet(false), initialColumnCount(0), initialEntryCountSet(false), initialEntryCount(0), forceInitialDimensions(false), hasCustomRowGrouping(!matrix.trivialRowGrouping), initialRowGroupCountSet(false), initialRowGroupCount(0), rowGroupIndices(), columnsAndValues(std::move(matrix.columnsAndValues)), rowIndications(std::move(matrix.rowIndications)), currentEntryCount(matrix.entryCount), currentRowGroupCount() { - + lastRow = matrix.rowCount == 0 ? 0 : matrix.rowCount - 1; lastColumn = columnsAndValues.empty() ? 0 : columnsAndValues.back().getColumn(); highestColumn = matrix.getColumnCount() == 0 ? 0 : matrix.getColumnCount() - 1; - + // If the matrix has a custom row grouping, we move it and remove the last element to make it 'open' again. if (hasCustomRowGrouping) { rowGroupIndices = std::move(matrix.rowGroupIndices); @@ -112,19 +112,19 @@ namespace storm { } currentRowGroupCount = rowGroupIndices->empty() ? 0 : rowGroupIndices.get().size() - 1; } - + // Likewise, we need to 'open' the row indications again. if (!rowIndications.empty()) { rowIndications.pop_back(); } } - + template void SparseMatrixBuilder::addNextValue(index_type row, index_type column, ValueType const& value) { // Check that we did not move backwards wrt. the row. STORM_LOG_THROW(row >= lastRow, storm::exceptions::InvalidArgumentException, "Adding an element in row " << row << ", but an element in row " << lastRow << " has already been added."); STORM_LOG_ASSERT(columnsAndValues.size() == currentEntryCount, "Unexpected size of columnsAndValues vector."); - + // Check if a diagonal entry shall be inserted before if (pendingDiagonalEntry) { index_type diagColumn = hasCustomRowGrouping ? currentRowGroupCount - 1 : lastRow; @@ -143,7 +143,7 @@ namespace storm { } } } - + // If the element is in the same row, but was not inserted in the correct order, we need to fix the row after // the insertion. bool fixCurrentRow = row == lastRow && column < lastColumn; @@ -159,26 +159,26 @@ namespace storm { rowIndications.resize(row + 1, currentEntryCount); lastRow = row; } - + lastColumn = column; - + // Finally, set the element and increase the current size. columnsAndValues.emplace_back(column, value); highestColumn = std::max(highestColumn, column); ++currentEntryCount; - + // If we need to fix the row, do so now. if (fixCurrentRow) { // First, we sort according to columns. std::sort(columnsAndValues.begin() + rowIndications.back(), columnsAndValues.end(), [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { return a.getColumn() < b.getColumn(); }); - + // Then, we eliminate possible duplicate entries. auto it = std::unique(columnsAndValues.begin() + rowIndications.back(), columnsAndValues.end(), [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { return a.getColumn() == b.getColumn(); }); - + // Finally, remove the superfluous elements. std::size_t elementsToRemove = std::distance(it, columnsAndValues.end()); if (elementsToRemove > 0) { @@ -188,7 +188,7 @@ namespace storm { } } } - + // In case we did not expect this value, we throw an exception. if (forceInitialDimensions) { STORM_LOG_THROW(!initialRowCountSet || lastRow < initialRowCount, storm::exceptions::OutOfRangeException, "Cannot insert value at illegal row " << lastRow << "."); @@ -196,12 +196,12 @@ namespace storm { STORM_LOG_THROW(!initialEntryCountSet || currentEntryCount <= initialEntryCount, storm::exceptions::OutOfRangeException, "Too many entries in matrix, expected only " << initialEntryCount << "."); } } - + template void SparseMatrixBuilder::newRowGroup(index_type startingRow) { STORM_LOG_THROW(hasCustomRowGrouping, storm::exceptions::InvalidStateException, "Matrix was not created to have a custom row grouping."); STORM_LOG_THROW(startingRow >= lastRow, storm::exceptions::InvalidStateException, "Illegal row group with negative size."); - + // If there still is a pending diagonal entry, we need to add it now (otherwise, the correct diagonal column will be unclear) if (pendingDiagonalEntry) { STORM_LOG_ASSERT(currentRowGroupCount > 0, "Diagonal entry was set before opening the first row group."); @@ -210,10 +210,10 @@ namespace storm { pendingDiagonalEntry = boost::none; // clear now, so addNextValue works properly addNextValue(lastRow, diagColumn, diagValue); } - + rowGroupIndices.get().push_back(startingRow); ++currentRowGroupCount; - + // Handle the case where the previous row group ends with one or more empty rows if (lastRow + 1 < startingRow) { // Close all rows from the most recent one to the starting row. @@ -224,10 +224,10 @@ namespace storm { lastColumn = 0; } } - + template SparseMatrix SparseMatrixBuilder::build(index_type overriddenRowCount, index_type overriddenColumnCount, index_type overriddenRowGroupCount) { - + // If there still is a pending diagonal entry, we need to add it now if (pendingDiagonalEntry) { index_type diagColumn = hasCustomRowGrouping ? currentRowGroupCount - 1 : lastRow; @@ -235,30 +235,30 @@ namespace storm { pendingDiagonalEntry = boost::none; // clear now, so addNextValue works properly addNextValue(lastRow, diagColumn, diagValue); } - + bool hasEntries = currentEntryCount != 0; - + uint_fast64_t rowCount = hasEntries ? lastRow + 1 : 0; - + // If the last row group was empty, we need to add one more to the row count, because otherwise this empty row is not counted. if (hasCustomRowGrouping) { if (lastRow < rowGroupIndices->back()) { ++rowCount; } } - + if (initialRowCountSet && forceInitialDimensions) { STORM_LOG_THROW(rowCount <= initialRowCount, storm::exceptions::InvalidStateException, "Expected not more than " << initialRowCount << " rows, but got " << rowCount << "."); rowCount = std::max(rowCount, initialRowCount); } - + rowCount = std::max(rowCount, overriddenRowCount); - + // If the current row count was overridden, we may need to add empty rows. for (index_type i = lastRow + 1; i < rowCount; ++i) { rowIndications.push_back(currentEntryCount); } - + // We put a sentinel element at the last position of the row indices array. This eases iteration work, // as now the indices of row i are always between rowIndications[i] and rowIndications[i + 1], also for // the first and last row. @@ -272,12 +272,12 @@ namespace storm { columnCount = std::max(columnCount, initialColumnCount); } columnCount = std::max(columnCount, overriddenColumnCount); - + uint_fast64_t entryCount = currentEntryCount; if (initialEntryCountSet && forceInitialDimensions) { STORM_LOG_THROW(entryCount == initialEntryCount, storm::exceptions::InvalidStateException, "Expected " << initialEntryCount << " entries, but got " << entryCount << "."); } - + // Check whether row groups are missing some entries. if (hasCustomRowGrouping) { uint_fast64_t rowGroupCount = currentRowGroupCount; @@ -286,15 +286,15 @@ namespace storm { rowGroupCount = std::max(rowGroupCount, initialRowGroupCount); } rowGroupCount = std::max(rowGroupCount, overriddenRowGroupCount); - + for (index_type i = currentRowGroupCount; i <= rowGroupCount; ++i) { rowGroupIndices.get().push_back(rowCount); } } - + return SparseMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); } - + template typename SparseMatrixBuilder::index_type SparseMatrixBuilder::getLastRow() const { return lastRow; @@ -313,7 +313,7 @@ namespace storm { typename SparseMatrixBuilder::index_type SparseMatrixBuilder::getLastColumn() const { return lastColumn; } - + // Debug method for printing the current matrix template void print(std::vector::index_type> const& rowGroupIndices, std::vector::index_type, typename SparseMatrix::value_type>> const& columnsAndValues, std::vector::index_type> const& rowIndications) { @@ -335,11 +335,11 @@ namespace storm { } } } - + template void SparseMatrixBuilder::replaceColumns(std::vector const& replacements, index_type offset) { index_type maxColumn = 0; - + for (index_type row = 0; row < rowIndications.size(); ++row) { bool changed = false; auto startRow = std::next(columnsAndValues.begin(), rowIndications[row]); @@ -365,11 +365,11 @@ namespace storm { }), "Columns not sorted."); } } - + highestColumn = maxColumn; lastColumn = columnsAndValues.empty() ? 0 : columnsAndValues.back().getColumn(); } - + template void SparseMatrixBuilder::addDiagonalEntry(index_type row, ValueType const& value) { STORM_LOG_THROW(row >= lastRow, storm::exceptions::InvalidArgumentException, "Adding a diagonal element in row " << row << ", but an element in row " << lastRow << " has already been added."); @@ -399,59 +399,59 @@ namespace storm { SparseMatrix::rows::rows(iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) { // Intentionally left empty. } - + template typename SparseMatrix::iterator SparseMatrix::rows::begin() { return beginIterator; } - + template typename SparseMatrix::iterator SparseMatrix::rows::end() { return beginIterator + entryCount; } - + template typename SparseMatrix::index_type SparseMatrix::rows::getNumberOfEntries() const { return this->entryCount; } - + template SparseMatrix::const_rows::const_rows(const_iterator begin, index_type entryCount) : beginIterator(begin), entryCount(entryCount) { // Intentionally left empty. } - + template typename SparseMatrix::const_iterator SparseMatrix::const_rows::begin() const { return beginIterator; } - + template typename SparseMatrix::const_iterator SparseMatrix::const_rows::end() const { return beginIterator + entryCount; } - + template typename SparseMatrix::index_type SparseMatrix::const_rows::getNumberOfEntries() const { return this->entryCount; } - + template SparseMatrix::SparseMatrix() : rowCount(0), columnCount(0), entryCount(0), nonzeroEntryCount(0), columnsAndValues(), rowIndications(), rowGroupIndices() { // Intentionally left empty. } - + template SparseMatrix::SparseMatrix(SparseMatrix const& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(other.columnsAndValues), rowIndications(other.rowIndications), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(other.rowGroupIndices) { // Intentionally left empty. } - + template SparseMatrix::SparseMatrix(SparseMatrix const& other, bool insertDiagonalElements) { storm::storage::BitVector rowConstraint(other.getRowCount(), true); storm::storage::BitVector columnConstraint(other.getColumnCount(), true); *this = other.getSubmatrix(false, rowConstraint, columnConstraint, insertDiagonalElements); } - + template SparseMatrix::SparseMatrix(SparseMatrix&& other) : rowCount(other.rowCount), columnCount(other.columnCount), entryCount(other.entryCount), nonzeroEntryCount(other.nonzeroEntryCount), columnsAndValues(std::move(other.columnsAndValues)), rowIndications(std::move(other.rowIndications)), trivialRowGrouping(other.trivialRowGrouping), rowGroupIndices(std::move(other.rowGroupIndices)) { // Now update the source matrix @@ -459,12 +459,12 @@ namespace storm { other.columnCount = 0; other.entryCount = 0; } - + template SparseMatrix::SparseMatrix(index_type columnCount, std::vector const& rowIndications, std::vector> const& columnsAndValues, boost::optional> const& rowGroupIndices) : rowCount(rowIndications.size() - 1), columnCount(columnCount), entryCount(columnsAndValues.size()), nonzeroEntryCount(0), columnsAndValues(columnsAndValues), rowIndications(rowIndications), trivialRowGrouping(!rowGroupIndices), rowGroupIndices(rowGroupIndices) { this->updateNonzeroEntryCount(); } - + template SparseMatrix::SparseMatrix(index_type columnCount, std::vector&& rowIndications, std::vector>&& columnsAndValues, boost::optional>&& rowGroupIndices) : columnCount(columnCount), nonzeroEntryCount(0), columnsAndValues(std::move(columnsAndValues)), rowIndications(std::move(rowIndications)), rowGroupIndices(std::move(rowGroupIndices)) { // Initialize some variables here which depend on other variables @@ -474,7 +474,7 @@ namespace storm { this->trivialRowGrouping = !this->rowGroupIndices; this->updateNonzeroEntryCount(); } - + template SparseMatrix& SparseMatrix::operator=(SparseMatrix const& other) { // Only perform assignment if source and target are not the same. @@ -483,7 +483,7 @@ namespace storm { columnCount = other.columnCount; entryCount = other.entryCount; nonzeroEntryCount = other.nonzeroEntryCount; - + columnsAndValues = other.columnsAndValues; rowIndications = other.rowIndications; rowGroupIndices = other.rowGroupIndices; @@ -491,7 +491,7 @@ namespace storm { } return *this; } - + template SparseMatrix& SparseMatrix::operator=(SparseMatrix&& other) { // Only perform assignment if source and target are not the same. @@ -500,7 +500,7 @@ namespace storm { columnCount = other.columnCount; entryCount = other.entryCount; nonzeroEntryCount = other.nonzeroEntryCount; - + columnsAndValues = std::move(other.columnsAndValues); rowIndications = std::move(other.rowIndications); rowGroupIndices = std::move(other.rowGroupIndices); @@ -508,15 +508,15 @@ namespace storm { } return *this; } - + template bool SparseMatrix::operator==(SparseMatrix const& other) const { if (this == &other) { return true; } - + bool equalityResult = true; - + equalityResult &= this->getRowCount() == other.getRowCount(); if (!equalityResult) { return false; @@ -533,7 +533,7 @@ namespace storm { if (!equalityResult) { return false; } - + // For the actual contents, we need to do a little bit more work, because we want to ignore elements that // are set to zero, please they may be represented implicitly in the other matrix. for (index_type row = 0; row < this->getRowCount(); ++row) { @@ -559,25 +559,25 @@ namespace storm { return false; } } - + return equalityResult; } - + template typename SparseMatrix::index_type SparseMatrix::getRowCount() const { return rowCount; } - + template typename SparseMatrix::index_type SparseMatrix::getColumnCount() const { return columnCount; } - + template typename SparseMatrix::index_type SparseMatrix::getEntryCount() const { return entryCount; } - + template uint_fast64_t SparseMatrix::getRowGroupEntryCount(uint_fast64_t const group) const { uint_fast64_t result = 0; @@ -590,12 +590,12 @@ namespace storm { } return result; } - + template typename SparseMatrix::index_type SparseMatrix::getNonzeroEntryCount() const { return nonzeroEntryCount; } - + template void SparseMatrix::updateNonzeroEntryCount() const { this->nonzeroEntryCount = 0; @@ -605,12 +605,12 @@ namespace storm { } } } - + template void SparseMatrix::updateNonzeroEntryCount(std::make_signed::type difference) { this->nonzeroEntryCount += difference; } - + template void SparseMatrix::updateDimensions() const { this->nonzeroEntryCount = 0; @@ -622,7 +622,7 @@ namespace storm { } } } - + template typename SparseMatrix::index_type SparseMatrix::getRowGroupCount() const { if (!this->hasTrivialRowGrouping()) { @@ -631,12 +631,12 @@ namespace storm { return rowCount; } } - + template typename SparseMatrix::index_type SparseMatrix::getRowGroupSize(index_type group) const { return this->getRowGroupIndices()[group + 1] - this->getRowGroupIndices()[group]; } - + template typename SparseMatrix::index_type SparseMatrix::getSizeOfLargestRowGroup() const { if (this->hasTrivialRowGrouping()) { @@ -650,7 +650,7 @@ namespace storm { } return res; } - + template typename SparseMatrix::index_type SparseMatrix::getNumRowsInRowGroups(storm::storage::BitVector const& groupConstraint) const { if (this->hasTrivialRowGrouping()) { @@ -669,7 +669,7 @@ namespace storm { return numRows; } - + template std::vector::index_type> const& SparseMatrix::getRowGroupIndices() const { // If there is no current row grouping, we need to create it. @@ -679,7 +679,7 @@ namespace storm { } return rowGroupIndices.get(); } - + template std::vector::index_type> SparseMatrix::swapRowGroupIndices(std::vector&& newRowGrouping) { std::vector result; @@ -689,7 +689,7 @@ namespace storm { } return result; } - + template void SparseMatrix::setRowGroupIndices(std::vector const& newRowGroupIndices) { trivialRowGrouping = false; @@ -700,7 +700,7 @@ namespace storm { bool SparseMatrix::hasTrivialRowGrouping() const { return trivialRowGrouping; } - + template void SparseMatrix::makeRowGroupingTrivial() { if (trivialRowGrouping) { @@ -710,7 +710,7 @@ namespace storm { rowGroupIndices = boost::none; } } - + template storm::storage::BitVector SparseMatrix::getRowFilter(storm::storage::BitVector const& groupConstraint) const { storm::storage::BitVector res(this->getRowCount(), false); @@ -722,7 +722,7 @@ namespace storm { } return res; } - + template storm::storage::BitVector SparseMatrix::getRowFilter(storm::storage::BitVector const& groupConstraint, storm::storage::BitVector const& columnConstraint) const { storm::storage::BitVector result(this->getRowCount(), false); @@ -743,7 +743,7 @@ namespace storm { } return result; } - + template storm::storage::BitVector SparseMatrix::getRowGroupFilter(storm::storage::BitVector const& rowConstraint, bool setIfForAllRowsInGroup) const { STORM_LOG_ASSERT(!this->hasTrivialRowGrouping(), "Tried to get a row group filter but this matrix does not have row groups"); @@ -766,14 +766,14 @@ namespace storm { } return result; } - + template void SparseMatrix::makeRowsAbsorbing(storm::storage::BitVector const& rows) { for (auto row : rows) { makeRowDirac(row, row); } } - + template void SparseMatrix::makeRowGroupsAbsorbing(storm::storage::BitVector const& rowGroupConstraint) { if (!this->hasTrivialRowGrouping()) { @@ -788,19 +788,19 @@ namespace storm { } } } - + template void SparseMatrix::makeRowDirac(index_type row, index_type column) { iterator columnValuePtr = this->begin(row); iterator columnValuePtrEnd = this->end(row); - + // If the row has no elements in it, we cannot make it absorbing, because we would need to move all elements // in the vector of nonzeros otherwise. if (columnValuePtr >= columnValuePtrEnd) { throw storm::exceptions::InvalidStateException() << "Illegal call to SparseMatrix::makeRowDirac: cannot make row " << row << " absorbing, because there is no entry in this row."; } iterator lastColumnValuePtr = this->end(row) - 1; - + // If there is at least one entry in this row, we can set it to one, modify its column value to the // one given by the parameter and set all subsequent elements of this row to zero. // However, we want to preserve that column indices within a row are ascending, so we pick an entry that is close to the desired column index @@ -824,7 +824,7 @@ namespace storm { columnValuePtr->setValue(storm::utility::zero()); } } - + template bool SparseMatrix::compareRows(index_type i1, index_type i2) const { const_iterator end1 = this->end(i1); @@ -841,7 +841,7 @@ namespace storm { } return false; } - + template BitVector SparseMatrix::duplicateRowsInRowgroups() const { BitVector bv(this->getRowCount()); @@ -856,31 +856,31 @@ namespace storm { } return bv; } - + template void SparseMatrix::swapRows(index_type const& row1, index_type const& row2) { if (row1 == row2) { return; } - + // Get the index of the row that has more / less entries than the other. index_type largerRow = getRow(row1).getNumberOfEntries() > getRow(row2).getNumberOfEntries() ? row1 : row2; index_type smallerRow = largerRow == row1 ? row2 : row1; index_type rowSizeDifference = getRow(largerRow).getNumberOfEntries() - getRow(smallerRow).getNumberOfEntries(); - + // Save contents of larger row. auto copyRow = getRow(largerRow); std::vector> largerRowContents(copyRow.begin(), copyRow.end()); - + if (largerRow < smallerRow) { auto writeIt = getRows(largerRow, smallerRow + 1).begin(); - + // Write smaller row to its new position. for (auto& smallerRowEntry : getRow(smallerRow)) { *writeIt = std::move(smallerRowEntry); ++writeIt; } - + // Write the intermediate rows into their correct position. if (!storm::utility::isZero(rowSizeDifference)) { for (auto& intermediateRowEntry : getRows(largerRow + 1, smallerRow)) { @@ -891,15 +891,15 @@ namespace storm { // skip the intermediate rows writeIt = getRow(smallerRow).begin(); } - + // Write the larger row to its new position. for (auto& largerRowEntry : largerRowContents) { *writeIt = std::move(largerRowEntry); ++writeIt; } - + STORM_LOG_ASSERT(writeIt == getRow(smallerRow).end(), "Unexpected position of write iterator."); - + // Update the row indications to account for the shift of indices at where the rows now start. if (!storm::utility::isZero(rowSizeDifference)) { for (index_type row = largerRow + 1; row <= smallerRow; ++row) { @@ -908,14 +908,14 @@ namespace storm { } } else { auto writeIt = getRows(smallerRow, largerRow + 1).end() - 1; - + // Write smaller row to its new position auto copyRow = getRow(smallerRow); for (auto smallerRowEntryIt = copyRow.end() - 1; smallerRowEntryIt != copyRow.begin() - 1; --smallerRowEntryIt) { *writeIt = std::move(*smallerRowEntryIt); --writeIt; } - + // Write the intermediate rows into their correct position. if (!storm::utility::isZero(rowSizeDifference)) { for (auto intermediateRowEntryIt = getRows(smallerRow + 1, largerRow).end() - 1; intermediateRowEntryIt != getRows(smallerRow + 1, largerRow).begin() - 1; --intermediateRowEntryIt) { @@ -926,15 +926,15 @@ namespace storm { // skip the intermediate rows writeIt = getRow(smallerRow).end() - 1; } - + // Write the larger row to its new position. for (auto largerRowEntryIt = largerRowContents.rbegin(); largerRowEntryIt != largerRowContents.rend(); ++largerRowEntryIt) { *writeIt = std::move(*largerRowEntryIt); --writeIt; } - + STORM_LOG_ASSERT(writeIt == getRow(smallerRow).begin() - 1, "Unexpected position of write iterator."); - + // Update row indications. // Update the row indications to account for the shift of indices at where the rows now start. if (!storm::utility::isZero(rowSizeDifference)) { @@ -944,11 +944,11 @@ namespace storm { } } } - + template std::vector SparseMatrix::getRowSumVector() const { std::vector result(this->getRowCount()); - + index_type row = 0; for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++row) { *resultIt = getRowSum(row); @@ -956,7 +956,7 @@ namespace storm { return result; } - + template ValueType SparseMatrix::getConstrainedRowSum(index_type row, storm::storage::BitVector const& constraint) const { ValueType result = storm::utility::zero(); @@ -967,7 +967,7 @@ namespace storm { } return result; } - + template std::vector SparseMatrix::getConstrainedRowSumVector(storm::storage::BitVector const& rowConstraint, storm::storage::BitVector const& columnConstraint) const { std::vector result(rowConstraint.getNumberOfSetBits()); @@ -977,7 +977,7 @@ namespace storm { } return result; } - + template std::vector SparseMatrix::getConstrainedRowGroupSumVector(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint) const { std::vector result; @@ -995,7 +995,7 @@ namespace storm { } return result; } - + template SparseMatrix SparseMatrix::getSubmatrix(bool useGroups, storm::storage::BitVector const& rowConstraint, storm::storage::BitVector const& columnConstraint, bool insertDiagonalElements, storm::storage::BitVector const& makeZeroColumns) const { if (useGroups) { @@ -1008,14 +1008,14 @@ namespace storm { *it = i; } auto res = getSubmatrix(rowConstraint, columnConstraint, fakeRowGroupIndices, insertDiagonalElements, makeZeroColumns); - + // Create a new row grouping that reflects the new sizes of the row groups if the current matrix has a // non trivial row-grouping. if (!this->hasTrivialRowGrouping()) { std::vector newRowGroupIndices; newRowGroupIndices.push_back(0); auto selectedRowIt = rowConstraint.begin(); - + // For this, we need to count how many rows were preserved in every group. for (uint_fast64_t group = 0; group < this->getRowGroupCount(); ++group) { uint_fast64_t newRowCount = 0; @@ -1027,20 +1027,20 @@ namespace storm { newRowGroupIndices.push_back(newRowGroupIndices.back() + newRowCount); } } - + res.trivialRowGrouping = false; res.rowGroupIndices = newRowGroupIndices; } - + return res; } } - + template SparseMatrix SparseMatrix::getSubmatrix(storm::storage::BitVector const& rowGroupConstraint, storm::storage::BitVector const& columnConstraint, std::vector const& rowGroupIndices, bool insertDiagonalEntries, storm::storage::BitVector const& makeZeroColumns) const { STORM_LOG_THROW(!rowGroupConstraint.empty() && !columnConstraint.empty(), storm::exceptions::InvalidArgumentException, "Cannot build empty submatrix."); uint_fast64_t submatrixColumnCount = columnConstraint.getNumberOfSetBits(); - + // Start by creating a temporary vector that stores for each index whose bit is set to true the number of // bits that were set before that particular index. std::vector columnBitsSetBeforeIndex = columnConstraint.getNumberOfSetBitsBeforeIndices(); @@ -1049,7 +1049,7 @@ namespace storm { tmp = std::make_unique>(rowGroupConstraint.getNumberOfSetBitsBeforeIndices()); } std::vector const& rowBitsSetBeforeIndex = tmp ? *tmp : columnBitsSetBeforeIndex; - + // Then, we need to determine the number of entries and the number of rows of the submatrix. index_type subEntries = 0; index_type subRows = 0; @@ -1058,17 +1058,17 @@ namespace storm { subRows += rowGroupIndices[index + 1] - rowGroupIndices[index]; for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) { bool foundDiagonalElement = false; - + for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { if (columnConstraint.get(it->getColumn()) && (makeZeroColumns.size() == 0 || !makeZeroColumns.get(it->getColumn())) ) { ++subEntries; - + if (columnBitsSetBeforeIndex[it->getColumn()] == rowBitsSetBeforeIndex[index]) { foundDiagonalElement = true; } } } - + // If requested, we need to reserve one entry more for inserting the diagonal zero entry. if (insertDiagonalEntries && !foundDiagonalElement && rowGroupCount < submatrixColumnCount) { ++subEntries; @@ -1076,10 +1076,10 @@ namespace storm { } ++rowGroupCount; } - + // Create and initialize resulting matrix. SparseMatrixBuilder matrixBuilder(subRows, submatrixColumnCount, subEntries, true, !this->hasTrivialRowGrouping()); - + // Copy over selected entries. rowGroupCount = 0; index_type rowCount = 0; @@ -1090,7 +1090,7 @@ namespace storm { } for (index_type i = rowGroupIndices[index]; i < rowGroupIndices[index + 1]; ++i) { bool insertedDiagonalElement = false; - + for (const_iterator it = this->begin(i), ite = this->end(i); it != ite; ++it) { if (columnConstraint.get(it->getColumn()) && (makeZeroColumns.size() == 0 || !makeZeroColumns.get(it->getColumn()))) { if (columnBitsSetBeforeIndex[it->getColumn()] == rowBitsSetBeforeIndex[index]) { @@ -1110,20 +1110,20 @@ namespace storm { } ++rowGroupCount; } - + return matrixBuilder.build(); } - + template SparseMatrix SparseMatrix::restrictRows(storm::storage::BitVector const& rowsToKeep, bool allowEmptyRowGroups) const { STORM_LOG_ASSERT(rowsToKeep.size() == this->getRowCount(), "Dimensions mismatch."); - + // Count the number of entries of the resulting matrix uint_fast64_t entryCount = 0; for (auto const& row : rowsToKeep) { entryCount += this->getRow(row).getNumberOfEntries(); } - + // Get the smallest row group index such that all row groups with at least this index are empty. uint_fast64_t firstTrailingEmptyRowGroup = this->getRowGroupCount(); for (auto groupIndexIt = this->getRowGroupIndices().rbegin() + 1; groupIndexIt != this->getRowGroupIndices().rend(); ++groupIndexIt) { @@ -1133,7 +1133,7 @@ namespace storm { --firstTrailingEmptyRowGroup; } STORM_LOG_THROW(allowEmptyRowGroups || firstTrailingEmptyRowGroup == this->getRowGroupCount(), storm::exceptions::InvalidArgumentException, "Empty rows are not allowed, but row group " << firstTrailingEmptyRowGroup << " is empty."); - + // build the matrix. The row grouping will always be considered as nontrivial. SparseMatrixBuilder builder(rowsToKeep.getNumberOfSetBits(), this->getColumnCount(), entryCount, true, true, this->getRowGroupCount()); uint_fast64_t newRow = 0; @@ -1150,12 +1150,12 @@ namespace storm { } STORM_LOG_THROW(allowEmptyRowGroups || !rowGroupEmpty, storm::exceptions::InvalidArgumentException, "Empty rows are not allowed, but row group " << rowGroup << " is empty."); } - + // The all remaining row groups will be empty. Note that it is not allowed to call builder.addNewGroup(...) if there are no more rows afterwards. SparseMatrix res = builder.build(); return res; } - + template SparseMatrix SparseMatrix::filterEntries(storm::storage::BitVector const& rowFilter) const { // Count the number of entries in the resulting matrix. @@ -1163,7 +1163,7 @@ namespace storm { for (auto const& row : rowFilter) { entryCount += getRow(row).getNumberOfEntries(); } - + // Build the resulting matrix. SparseMatrixBuilder builder(getRowCount(), getColumnCount(), entryCount); for (auto const& row : rowFilter) { @@ -1172,14 +1172,14 @@ namespace storm { } } SparseMatrix result = builder.build(); - + // Add a row grouping if necessary. if (!hasTrivialRowGrouping()) { result.setRowGroupIndices(getRowGroupIndices()); } return result; } - + template void SparseMatrix::dropZeroEntries() { updateNonzeroEntryCount(); @@ -1200,7 +1200,7 @@ namespace storm { *this = std::move(result); } } - + template SparseMatrix SparseMatrix::selectRowsFromRowGroups(std::vector const& rowGroupToRowIndexMapping, bool insertDiagonalEntries) const { // First, we need to count how many non-zero entries the resulting matrix will have and reserve space for @@ -1209,7 +1209,7 @@ namespace storm { for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) { // Determine which row we need to select from the current row group. index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; - + // Iterate through that row and count the number of slots we have to reserve for copying. bool foundDiagonalElement = false; for (const_iterator it = this->begin(rowToCopy), ite = this->end(rowToCopy); it != ite; ++it) { @@ -1222,15 +1222,15 @@ namespace storm { ++subEntries; } } - + // Now create the matrix to be returned with the appropriate size. SparseMatrixBuilder matrixBuilder(rowGroupIndices.get().size() - 1, columnCount, subEntries); - + // Copy over the selected lines from the source matrix. for (index_type rowGroupIndex = 0, rowGroupIndexEnd = rowGroupToRowIndexMapping.size(); rowGroupIndex < rowGroupIndexEnd; ++rowGroupIndex) { // Determine which row we need to select from the current row group. index_type rowToCopy = this->getRowGroupIndices()[rowGroupIndex] + rowGroupToRowIndexMapping[rowGroupIndex]; - + // Iterate through that row and copy the entries. This also inserts a zero element on the diagonal if // there is no entry yet. bool insertedDiagonalElement = false; @@ -1247,7 +1247,7 @@ namespace storm { matrixBuilder.addNextValue(rowGroupIndex, rowGroupIndex, storm::utility::zero()); } } - + // Finalize created matrix and return result. return matrixBuilder.build(); } @@ -1317,7 +1317,7 @@ namespace storm { } return result; } - + template SparseMatrix SparseMatrix::transpose(bool joinGroups, bool keepZeros) const { index_type rowCount = this->getColumnCount(); @@ -1329,10 +1329,10 @@ namespace storm { this->updateNonzeroEntryCount(); entryCount = this->getNonzeroEntryCount(); } - + std::vector rowIndications(rowCount + 1); std::vector> columnsAndValues(entryCount); - + // First, we need to count how many entries each column has. for (index_type group = 0; group < columnCount; ++group) { for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) { @@ -1341,17 +1341,17 @@ namespace storm { } } } - + // Now compute the accumulated offsets. for (index_type i = 1; i < rowCount + 1; ++i) { rowIndications[i] = rowIndications[i - 1] + rowIndications[i]; } - + // Create an array that stores the index for the next value to be added for // each row in the transposed matrix. Initially this corresponds to the previously // computed accumulated offsets. std::vector nextIndices = rowIndications; - + // Now we are ready to actually fill in the values of the transposed matrix. for (index_type group = 0; group < columnCount; ++group) { for (auto const& transition : joinGroups ? this->getRowGroup(group) : this->getRow(group)) { @@ -1361,17 +1361,17 @@ namespace storm { } } } - + storm::storage::SparseMatrix transposedMatrix(columnCount, std::move(rowIndications), std::move(columnsAndValues), boost::none); - + return transposedMatrix; } - + template SparseMatrix SparseMatrix::transposeSelectedRowsFromRowGroups(std::vector const& rowGroupChoices, bool keepZeros) const { index_type rowCount = this->getColumnCount(); index_type columnCount = this->getRowGroupCount(); - + // Get the overall entry count as well as the number of entries of each column index_type entryCount = 0; std::vector rowIndications(columnCount + 1); @@ -1384,19 +1384,19 @@ namespace storm { } } } - + // Now compute the accumulated offsets. for (index_type i = 1; i < rowCount + 1; ++i) { rowIndications[i] = rowIndications[i - 1] + rowIndications[i]; } - + std::vector> columnsAndValues(entryCount); - + // Create an array that stores the index for the next value to be added for // each row in the transposed matrix. Initially this corresponds to the previously // computed accumulated offsets. std::vector nextIndices = rowIndications; - + // Now we are ready to actually fill in the values of the transposed matrix. rowGroupChoiceIt = rowGroupChoices.begin(); for (index_type rowGroup = 0; rowGroup < columnCount; ++rowGroup, ++rowGroupChoiceIt) { @@ -1407,16 +1407,16 @@ namespace storm { } } } - + return storm::storage::SparseMatrix(std::move(columnCount), std::move(rowIndications), std::move(columnsAndValues), boost::none); } - + template void SparseMatrix::convertToEquationSystem() { invertDiagonal(); negateAllNonDiagonalEntries(); } - + template void SparseMatrix::invertDiagonal() { // Now iterate over all row groups and set the diagonal elements to the inverted value. @@ -1439,14 +1439,14 @@ namespace storm { foundDiagonalElement = true; } } - + // Throw an exception if a row did not have an element on the diagonal. if (!foundDiagonalElement) { throw storm::exceptions::InvalidArgumentException() << "Illegal call to SparseMatrix::invertDiagonal: matrix is missing diagonal entries."; } } } - + template void SparseMatrix::negateAllNonDiagonalEntries() { // Iterate over all row groups and negate all the elements that are not on the diagonal. @@ -1458,7 +1458,7 @@ namespace storm { } } } - + template void SparseMatrix::deleteDiagonalEntries() { // Iterate over all rows and negate all the elements that are not on the diagonal. @@ -1471,15 +1471,15 @@ namespace storm { } } } - + template typename std::pair, std::vector> SparseMatrix::getJacobiDecomposition() const { STORM_LOG_THROW(this->getRowCount() == this->getColumnCount(), storm::exceptions::InvalidArgumentException, "Canno compute Jacobi decomposition of non-square matrix."); - + // Prepare the resulting data structures. SparseMatrixBuilder luBuilder(this->getRowCount(), this->getColumnCount()); std::vector invertedDiagonal(rowCount); - + // Copy entries to the appropriate matrices. for (index_type rowNumber = 0; rowNumber < rowCount; ++rowNumber) { for (const_iterator it = this->begin(rowNumber), ite = this->end(rowNumber); it != ite; ++it) { @@ -1490,22 +1490,22 @@ namespace storm { } } } - + return std::make_pair(luBuilder.build(), std::move(invertedDiagonal)); } - + #ifdef STORM_HAVE_CARL template<> typename std::pair, std::vector> SparseMatrix::getJacobiDecomposition() const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported."); } - + template<> typename std::pair, std::vector> SparseMatrix::getJacobiDecomposition() const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported."); } #endif - + template template ResultValueType SparseMatrix::getPointwiseProductRowSum(storm::storage::SparseMatrix const& otherMatrix, index_type const& row) const { @@ -1513,7 +1513,7 @@ namespace storm { typename storm::storage::SparseMatrix::const_iterator ite1 = this->end(row); typename storm::storage::SparseMatrix::const_iterator it2 = otherMatrix.begin(row); typename storm::storage::SparseMatrix::const_iterator ite2 = otherMatrix.end(row); - + ResultValueType result = storm::utility::zero(); for (;it1 != ite1 && it2 != ite2; ++it1) { if (it1->getColumn() < it2->getColumn()) { @@ -1529,7 +1529,7 @@ namespace storm { } return result; } - + template template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const { @@ -1540,7 +1540,7 @@ namespace storm { } return result; } - + template void SparseMatrix::multiplyWithVector(std::vector const& vector, std::vector& result, std::vector const* summand) const { // If the vector and the result are aliases and this is not set to be allowed, we need and temporary vector. @@ -1553,14 +1553,14 @@ namespace storm { } else { target = &result; } - + this->multiplyWithVectorForward(vector, *target, summand); - + if (target == &temporary) { std::swap(result, *target); } } - + template void SparseMatrix::multiplyWithVectorForward(std::vector const& vector, std::vector& result, std::vector const* summand) const { const_iterator it = this->begin(); @@ -1572,7 +1572,7 @@ namespace storm { if (summand) { summandIterator = summand->begin(); } - + for (; resultIterator != resultIteratorEnd; ++rowIterator, ++resultIterator, ++summandIterator) { ValueType newValue; if (summand) { @@ -1580,15 +1580,15 @@ namespace storm { } else { newValue = storm::utility::zero(); } - + for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) { newValue += it->getValue() * vector[it->getColumn()]; } - + *resultIterator = newValue; } } - + template void SparseMatrix::multiplyWithVectorBackward(std::vector const& vector, std::vector& result, std::vector const* summand) const { const_iterator it = this->end() - 1; @@ -1600,7 +1600,7 @@ namespace storm { if (summand) { summandIterator = summand->end() - 1; } - + for (; resultIterator != resultIteratorEnd; --rowIterator, --resultIterator, --summandIterator) { ValueType newValue; if (summand) { @@ -1608,15 +1608,15 @@ namespace storm { } else { newValue = storm::utility::zero(); } - + for (ite = this->begin() + *rowIterator - 1; it != ite; --it) { newValue += (it->getValue() * vector[it->getColumn()]); } - + *resultIterator = newValue; } } - + #ifdef STORM_HAVE_INTELTBB template class TbbMultAddFunctor { @@ -1624,11 +1624,11 @@ namespace storm { typedef typename storm::storage::SparseMatrix::index_type index_type; typedef typename storm::storage::SparseMatrix::value_type value_type; typedef typename storm::storage::SparseMatrix::const_iterator const_iterator; - + TbbMultAddFunctor(std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand) : columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand) { // Intentionally left empty. } - + void operator()(tbb::blocked_range const& range) const { index_type startRow = range.begin(); index_type endRow = range.end(); @@ -1641,18 +1641,18 @@ namespace storm { if (summand) { summandIterator = summand->begin() + startRow; } - + for (; resultIterator != resultIteratorEnd; ++rowIterator, ++resultIterator, ++summandIterator) { ValueType newValue = summand ? *summandIterator : storm::utility::zero(); - + for (ite = columnsAndEntries.begin() + *(rowIterator + 1); it != ite; ++it) { newValue += it->getValue() * x[it->getColumn()]; } - + *resultIterator = newValue; } } - + private: std::vector> const& columnsAndEntries; std::vector const& rowIndications; @@ -1660,7 +1660,7 @@ namespace storm { std::vector& result; std::vector const* summand; }; - + template void SparseMatrix::multiplyWithVectorParallel(std::vector const& vector, std::vector& result, std::vector const* summand) const { if (&vector == &result) { @@ -1673,7 +1673,7 @@ namespace storm { } } #endif - + template ValueType SparseMatrix::multiplyRowWithVector(index_type row, std::vector const& vector) const { ValueType result = storm::utility::zero(); @@ -1683,7 +1683,7 @@ namespace storm { } return result; } - + template void SparseMatrix::performSuccessiveOverRelaxationStep(ValueType omega, std::vector& x, std::vector const& b) const { const_iterator it = this->end() - 1; @@ -1692,13 +1692,13 @@ namespace storm { typename std::vector::const_iterator bIt = b.end() - 1; typename std::vector::iterator resultIterator = x.end() - 1; typename std::vector::iterator resultIteratorEnd = x.begin() - 1; - + index_type currentRow = getRowCount(); for (; resultIterator != resultIteratorEnd; --rowIterator, --resultIterator, --bIt) { --currentRow; ValueType tmpValue = storm::utility::zero(); ValueType diagonalElement = storm::utility::zero(); - + for (ite = this->begin() + *rowIterator - 1; it != ite; --it) { if (it->getColumn() != currentRow) { tmpValue += it->getValue() * x[it->getColumn()]; @@ -1710,14 +1710,14 @@ namespace storm { *resultIterator = ((storm::utility::one() - omega) * *resultIterator) + (omega / diagonalElement) * (*bIt - tmpValue); } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::performSuccessiveOverRelaxationStep(Interval, std::vector&, std::vector const&) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } #endif - + template void SparseMatrix::performWalkerChaeStep(std::vector const& x, std::vector const& columnSums, std::vector const& b, std::vector const& ax, std::vector& result) const { const_iterator it = this->begin(); @@ -1735,7 +1735,7 @@ namespace storm { result[it->getColumn()] += it->getValue() * (b[row] / ax[row]); } } - + auto xIterator = x.begin(); auto sumsIterator = columnSums.begin(); for (auto& entry : result) { @@ -1751,7 +1751,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } #endif - + template void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { if (dir == OptimizationDirection::Minimize) { @@ -1776,36 +1776,36 @@ namespace storm { if (choices) { choiceIt = choices->begin(); } - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; - + uint64_t currentRow = 0; for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++choiceIt, ++rowGroupIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { currentValue = *summandIt; ++summandIt; } - + for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - + if (choices) { selectedChoice = 0; if (*choiceIt == 0) { oldSelectedChoiceValue = currentValue; } } - + ++rowIt; ++currentRow; - + for (; currentRow < *(rowGroupIt + 1); ++rowIt, ++currentRow) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { @@ -1815,7 +1815,7 @@ namespace storm { if (choices && currentRow == *choiceIt + *rowGroupIt) { oldSelectedChoiceValue = newValue; } - + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { @@ -1826,7 +1826,7 @@ namespace storm { ++summandIt; } } - + // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { @@ -1835,14 +1835,14 @@ namespace storm { } } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } #endif - + template void SparseMatrix::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { if (dir == storm::OptimizationDirection::Minimize) { @@ -1851,7 +1851,7 @@ namespace storm { multiplyAndReduceBackward>(rowGroupIndices, vector, summand, result, choices); } } - + template template void SparseMatrix::multiplyAndReduceBackward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { @@ -1867,22 +1867,22 @@ namespace storm { if (choices) { choiceIt = choices->end() - 1; } - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; - + uint64_t currentRow = this->getRowCount() - 1; for (auto resultIt = result.end() - 1, resultIte = result.begin() - 1; resultIt != resultIte; --resultIt, --choiceIt, --rowGroupIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { currentValue = *summandIt; --summandIt; } - + for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } @@ -1894,17 +1894,17 @@ namespace storm { } --rowIt; --currentRow; - + for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, --currentRow, ++i, --summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - + if (choices && currentRow == *choiceIt + *rowGroupIt) { oldSelectedChoiceValue = newValue; } - + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { @@ -1912,7 +1912,7 @@ namespace storm { } } } - + // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { @@ -1921,14 +1921,14 @@ namespace storm { } } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } #endif - + #ifdef STORM_HAVE_INTELTBB template class TbbMultAddReduceFunctor { @@ -1936,16 +1936,16 @@ namespace storm { typedef typename storm::storage::SparseMatrix::index_type index_type; typedef typename storm::storage::SparseMatrix::value_type value_type; typedef typename storm::storage::SparseMatrix::const_iterator const_iterator; - + TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand, std::vector* choices) : rowGroupIndices(rowGroupIndices), columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand), choices(choices) { // Intentionally left empty. } - + void operator()(tbb::blocked_range const& range) const { auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); - + auto rowIt = rowIndications.begin() + *groupIt; auto elementIt = columnsAndEntries.begin() + *rowIt; typename std::vector::const_iterator summandIt; @@ -1956,9 +1956,9 @@ namespace storm { if (choices) { choiceIt = choices->begin() + range.begin(); } - + auto resultIt = result.begin() + range.begin(); - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; @@ -1966,7 +1966,7 @@ namespace storm { uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*groupIt < *(groupIt + 1)) { if (summand) { @@ -1977,23 +1977,23 @@ namespace storm { for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { currentValue += elementIt->getValue() * x[elementIt->getColumn()]; } - + if (choices) { selectedChoice = 0; if (*choiceIt == 0) { oldSelectedChoiceValue = currentValue; } } - + ++rowIt; ++currentRow; - + for (; currentRow < *(groupIt + 1); ++rowIt, ++currentRow, ++summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * x[elementIt->getColumn()]; } - + if (choices && currentRow == *choiceIt + *groupIt) { oldSelectedChoiceValue = newValue; } @@ -2005,7 +2005,7 @@ namespace storm { } } } - + // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { @@ -2014,7 +2014,7 @@ namespace storm { } } } - + private: Compare compare; std::vector const& rowGroupIndices; @@ -2025,7 +2025,7 @@ namespace storm { std::vector const* summand; std::vector* choices; }; - + template void SparseMatrix::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { if (dir == storm::OptimizationDirection::Minimize) { @@ -2034,7 +2034,7 @@ namespace storm { tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { @@ -2042,10 +2042,10 @@ namespace storm { } #endif #endif - + template void SparseMatrix::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - + // If the vector and the result are aliases, we need and temporary vector. std::vector* target; std::vector temporary; @@ -2056,21 +2056,21 @@ namespace storm { } else { target = &result; } - + this->multiplyAndReduceForward(dir, rowGroupIndices, vector, summand, *target, choices); if (target == &temporary) { std::swap(temporary, result); } } - + template void SparseMatrix::multiplyVectorWithMatrix(std::vector const& vector, std::vector& result) const { const_iterator it = this->begin(); const_iterator ite; std::vector::const_iterator rowIterator = rowIndications.begin(); std::vector::const_iterator rowIteratorEnd = rowIndications.end(); - + uint_fast64_t currentRow = 0; for (; rowIterator != rowIteratorEnd - 1; ++rowIterator) { for (ite = this->begin() + *(rowIterator + 1); it != ite; ++it) { @@ -2079,7 +2079,7 @@ namespace storm { ++currentRow; } } - + template void SparseMatrix::scaleRowsInPlace(std::vector const& factors) { STORM_LOG_ASSERT(factors.size() == this->getRowCount(), "Can not scale rows: Number of rows and number of scaling factors do not match."); @@ -2091,7 +2091,7 @@ namespace storm { ++row; } } - + template void SparseMatrix::divideRowsInPlace(std::vector const& divisors) { STORM_LOG_ASSERT(divisors.size() == this->getRowCount(), "Can not divide rows: Number of rows and number of divisors do not match."); @@ -2104,34 +2104,34 @@ namespace storm { ++row; } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::divideRowsInPlace(std::vector const&) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This operation is not supported."); } #endif - + template typename SparseMatrix::const_rows SparseMatrix::getRows(index_type startRow, index_type endRow) const { return const_rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]); } - + template typename SparseMatrix::rows SparseMatrix::getRows(index_type startRow, index_type endRow) { return rows(this->columnsAndValues.begin() + this->rowIndications[startRow], this->rowIndications[endRow] - this->rowIndications[startRow]); } - + template typename SparseMatrix::const_rows SparseMatrix::getRow(index_type row) const { return getRows(row, row + 1); } - + template typename SparseMatrix::rows SparseMatrix::getRow(index_type row) { return getRows(row, row + 1); } - + template typename SparseMatrix::const_rows SparseMatrix::getRow(index_type rowGroup, index_type offset) const { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); @@ -2142,7 +2142,7 @@ namespace storm { return getRow(this->getRowGroupIndices()[rowGroup] + offset); } } - + template typename SparseMatrix::rows SparseMatrix::getRow(index_type rowGroup, index_type offset) { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); @@ -2154,8 +2154,8 @@ namespace storm { return getRow(rowGroup + offset); } } - - + + template typename SparseMatrix::const_rows SparseMatrix::getRowGroup(index_type rowGroup) const { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); @@ -2165,7 +2165,7 @@ namespace storm { return getRows(rowGroup, rowGroup + 1); } } - + template typename SparseMatrix::rows SparseMatrix::getRowGroup(index_type rowGroup) { STORM_LOG_ASSERT(rowGroup < this->getRowGroupCount(), "Row group is out-of-bounds."); @@ -2175,32 +2175,32 @@ namespace storm { return getRows(rowGroup, rowGroup + 1); } } - + template typename SparseMatrix::const_iterator SparseMatrix::begin(index_type row) const { return this->columnsAndValues.begin() + this->rowIndications[row]; } - + template typename SparseMatrix::iterator SparseMatrix::begin(index_type row) { return this->columnsAndValues.begin() + this->rowIndications[row]; } - + template typename SparseMatrix::const_iterator SparseMatrix::end(index_type row) const { return this->columnsAndValues.begin() + this->rowIndications[row + 1]; } - + template typename SparseMatrix::iterator SparseMatrix::end(index_type row) { return this->columnsAndValues.begin() + this->rowIndications[row + 1]; } - + template typename SparseMatrix::const_iterator SparseMatrix::end() const { return this->columnsAndValues.begin() + this->rowIndications[rowCount]; } - + template typename SparseMatrix::iterator SparseMatrix::end() { return this->columnsAndValues.begin() + this->rowIndications[rowCount]; @@ -2214,7 +2214,7 @@ namespace storm { } return sum; } - + template typename SparseMatrix::index_type SparseMatrix::getNonconstantEntryCount() const { index_type nonConstEntries = 0; @@ -2225,7 +2225,7 @@ namespace storm { } return nonConstEntries; } - + template typename SparseMatrix::index_type SparseMatrix::getNonconstantRowGroupCount() const { index_type nonConstRowGroups = 0; @@ -2239,7 +2239,7 @@ namespace storm { } return nonConstRowGroups; } - + template bool SparseMatrix::isProbabilistic() const { storm::utility::ConstantsComparator comparator; @@ -2258,7 +2258,7 @@ namespace storm { } return true; } - + template template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const { @@ -2269,7 +2269,7 @@ namespace storm { if (!this->hasTrivialRowGrouping() && matrix.hasTrivialRowGrouping()) return false; if (!this->hasTrivialRowGrouping() && !matrix.hasTrivialRowGrouping() && this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false; if (this->getRowGroupIndices() != matrix.getRowGroupIndices()) return false; - + // Check the subset property for all rows individually. for (index_type row = 0; row < this->getRowCount(); ++row) { auto it2 = matrix.begin(row); @@ -2286,7 +2286,7 @@ namespace storm { } return true; } - + template bool SparseMatrix::isIdentityMatrix() const { if (this->getRowCount() != this->getColumnCount()) { @@ -2326,7 +2326,7 @@ namespace storm { return result; } - + template std::ostream& operator<<(std::ostream& out, SparseMatrix const& matrix) { // Print column numbers in header. @@ -2335,22 +2335,22 @@ namespace storm { out << i << "\t"; } out << std::endl; - + // Iterate over all row groups. for (typename SparseMatrix::index_type group = 0; group < matrix.getRowGroupCount(); ++group) { out << "\t---- group " << group << "/" << (matrix.getRowGroupCount() - 1) << " ---- " << std::endl; typename SparseMatrix::index_type start = matrix.hasTrivialRowGrouping() ? group : matrix.getRowGroupIndices()[group]; typename SparseMatrix::index_type end = matrix.hasTrivialRowGrouping() ? group + 1 : matrix.getRowGroupIndices()[group + 1]; - + for (typename SparseMatrix::index_type i = start; i < end; ++i) { typename SparseMatrix::index_type nextIndex = matrix.rowIndications[i]; - + // Print the actual row. out << i << "\t(\t"; typename SparseMatrix::index_type currentRealIndex = 0; while (currentRealIndex < matrix.columnCount) { if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].getColumn()) { - out << matrix.columnsAndValues[nextIndex].getValue() << "\t"; + out << std::setprecision(3) << matrix.columnsAndValues[nextIndex].getValue() << "\t"; ++nextIndex; } else { out << "0\t"; @@ -2360,17 +2360,17 @@ namespace storm { out << "\t)\t" << i << std::endl; } } - + // Print column numbers in footer. out << "\t\t"; for (typename SparseMatrix::index_type i = 0; i < matrix.getColumnCount(); ++i) { out << i << "\t"; } out << std::endl; - + return out; } - + template void SparseMatrix::printAsMatlabMatrix(std::ostream& out) const { // Iterate over all row groups. @@ -2378,7 +2378,7 @@ namespace storm { STORM_LOG_ASSERT(this->getRowGroupSize(group) == 1, "Incorrect row group size."); for (typename SparseMatrix::index_type i = this->getRowGroupIndices()[group]; i < this->getRowGroupIndices()[group + 1]; ++i) { typename SparseMatrix::index_type nextIndex = this->rowIndications[i]; - + // Print the actual row. out << i << "\t("; typename SparseMatrix::index_type currentRealIndex = 0; @@ -2395,11 +2395,11 @@ namespace storm { } } } - + template std::size_t SparseMatrix::hash() const { std::size_t result = 0; - + boost::hash_combine(result, this->getRowCount()); boost::hash_combine(result, this->getColumnCount()); boost::hash_combine(result, this->getEntryCount()); @@ -2408,11 +2408,11 @@ namespace storm { if (!this->hasTrivialRowGrouping()) { boost::hash_combine(result, boost::hash_range(rowGroupIndices.get().begin(), rowGroupIndices.get().end())); } - + return result; } - - + + #ifdef STORM_HAVE_CARL std::set getVariables(SparseMatrix const& matrix) { @@ -2422,9 +2422,9 @@ namespace storm { } return result; } - + #endif - + // Explicitly instantiate the entry, builder and the matrix. // double template class MatrixEntry::index_type, double>; @@ -2435,10 +2435,10 @@ namespace storm { template double SparseMatrix::getPointwiseProductRowSum(storm::storage::SparseMatrix const& otherMatrix, typename SparseMatrix::index_type const& row) const; template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + template class MatrixEntry; template std::ostream& operator<<(std::ostream& out, MatrixEntry const& entry); - + // float template class MatrixEntry::index_type, float>; template std::ostream& operator<<(std::ostream& out, MatrixEntry::index_type, float> const& entry); @@ -2448,7 +2448,7 @@ namespace storm { template float SparseMatrix::getPointwiseProductRowSum(storm::storage::SparseMatrix const& otherMatrix, typename SparseMatrix::index_type const& row) const; template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + // int template class MatrixEntry::index_type, int>; template std::ostream& operator<<(std::ostream& out, MatrixEntry::index_type, int> const& entry); @@ -2456,7 +2456,7 @@ namespace storm { template class SparseMatrix; template std::ostream& operator<<(std::ostream& out, SparseMatrix const& matrix); template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + // state_type template class MatrixEntry::index_type, storm::storage::sparse::state_type>; template std::ostream& operator<<(std::ostream& out, MatrixEntry::index_type, storm::storage::sparse::state_type> const& entry); @@ -2464,10 +2464,10 @@ namespace storm { template class SparseMatrix; template std::ostream& operator<<(std::ostream& out, SparseMatrix const& matrix); template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + #ifdef STORM_HAVE_CARL // Rational Numbers - + #if defined(STORM_HAVE_CLN) template class MatrixEntry::index_type, ClnRationalNumber>; template std::ostream& operator<<(std::ostream& out, MatrixEntry const& entry); @@ -2478,7 +2478,7 @@ namespace storm { template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; #endif - + #if defined(STORM_HAVE_GMP) template class MatrixEntry::index_type, GmpRationalNumber>; template std::ostream& operator<<(std::ostream& out, MatrixEntry const& entry); @@ -2489,7 +2489,7 @@ namespace storm { template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; #endif - + // Rational Function template class MatrixEntry::index_type, RationalFunction>; template std::ostream& operator<<(std::ostream& out, MatrixEntry const& entry); @@ -2505,7 +2505,7 @@ namespace storm { template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + // Intervals template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template class MatrixEntry::index_type, Interval>; @@ -2515,13 +2515,10 @@ namespace storm { template std::ostream& operator<<(std::ostream& out, SparseMatrix const& matrix); template std::vector SparseMatrix::getPointwiseProductRowSumVector(storm::storage::SparseMatrix const& otherMatrix) const; template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; - + template bool SparseMatrix::isSubmatrixOf(SparseMatrix const& matrix) const; #endif - - - } // namespace storage -} // namespace storm - + } // namespace storage +} // namespace storm From 7b59f4c7559899e72de85fd54b326d0bcd910ae7 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Tue, 19 Jan 2021 17:25:21 +0100 Subject: [PATCH 44/50] adaptations for lra computation in GMMXXMultiplier Still WIP! --- .../infinitehorizon/internal/LraViHelper.cpp | 23 +++++++++++-------- src/storm/solver/GmmxxMultiplier.cpp | 3 ++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp index da16522f1..e5aeecdd3 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp @@ -185,6 +185,12 @@ namespace storm { // Check if we are done auto convergenceCheckResult = checkConvergence(relative, precision); result = convergenceCheckResult.currentValue; + + if(gameNondetTs() && iter > 1) { + xOld() = xOldTemp; + xNew() = xNewTemp; + } + if (convergenceCheckResult.isPrecisionAchieved) { break; } @@ -192,13 +198,11 @@ namespace storm { break; } - if(gameNondetTs() && iter > 1) { - xOld() = xOldTemp; - xNew() = xNewTemp; - } // If there will be a next iteration, we have to prepare it. - prepareNextIteration(env); + if(!gameNondetTs()) { + prepareNextIteration(env); + } } if (maxIter.is_initialized() && iter == maxIter.get()) { @@ -211,17 +215,18 @@ namespace storm { if (choices) { // We will be doing one more iteration step and track scheduler choices this time. - prepareNextIteration(env); + if(!gameNondetTs()) { + prepareNextIteration(env); + } performIterationStep(env, dir, choices); } std::cout << "result (" << iter << " steps):" << std::endl; - for(int i = 0; i < xNew().size() ; i++ ) { - std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl; - //if(i == 50) {std::cout << "only showing top 50 lines"; break; } + storm::utility::vector::applyPointwise(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; }); for(int i = 0; i < xNew().size() ; i++ ) { std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl; //if(i == 50) {std::cout << "only showing top 50 lines"; break; } } + if(gameNondetTs()) result = xOld().at(0) * _uniformizationRate; // TODO is "init" always going to be .at(0) ? return result; } diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 0a2843824..a75ab623f 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -228,6 +228,7 @@ namespace storm { } //std::cout << newValue << ", "; //STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits::row(itr), x) << " + " << *add_it << "; "); + if(this->isOverridden(currentRowGroup) ? compare(currentValue, newValue) : compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; @@ -250,7 +251,7 @@ namespace storm { // Finally write value to target vector. *target_it = currentValue; if(choices) { - if(this->isOverridden(currentRowGroup) ? !compare(currentValue, oldSelectedChoiceValue) : compare(currentValue, oldSelectedChoiceValue) ) { + if(this->isOverridden(currentRowGroup) ? compare(oldSelectedChoiceValue, currentValue) : compare(currentValue, oldSelectedChoiceValue) ) { *choice_it = selectedChoice; } } From d1f99e0548ea939f222151e8b2ef7570ceb3419c Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 20 Jan 2021 10:42:00 +0100 Subject: [PATCH 45/50] refactored canHandle check in rpatl model checker According to/stolen from 6c0cbe622 --- src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp index cedc64ae7..35464513d 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -41,11 +41,7 @@ namespace storm { template bool SparseSmgRpatlModelChecker::canHandleStatic(CheckTask const& checkTask, bool* requiresSingleInitialState) { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::rpatl().setGameFormulasAllowed(true).setRewardOperatorsAllowed(true).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageOperatorsAllowed(true))) { - return true; - } else { - return false; - } + return formula.isInFragment(storm::logic::rpatl()); } template From 1cdfb6b5d41d21fe5a8caac680c7cca1d68e8c49 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Wed, 20 Jan 2021 10:42:49 +0100 Subject: [PATCH 46/50] allowing reachability prob formulas in rpatl --- src/storm/logic/FragmentSpecification.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index 96cbaf181..836b020aa 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -63,6 +63,9 @@ namespace storm { rpatl.setLongRunAverageRewardFormulasAllowed(true); rpatl.setLongRunAverageOperatorsAllowed(true); + rpatl.setProbabilityOperatorsAllowed(true); + rpatl.setReachabilityProbabilityFormulasAllowed(true); + return rpatl; } From 9a8e8fec5fe43cc6d0f77f98299cdc7d0aebb01d Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 28 Jan 2021 18:20:08 +0100 Subject: [PATCH 47/50] renamed function argument --- src/storm/api/verification.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index d6d4969d4..868c00be3 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -264,7 +264,7 @@ namespace storm { } template - typename std::enable_if::value, std::unique_ptr>::type verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr> const& mdp, storm::modelchecker::CheckTask const& task) { + typename std::enable_if::value, std::unique_ptr>::type verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr> const& smg, storm::modelchecker::CheckTask const& task) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sparse engine cannot verify SMGs with this data type."); } From 4a018c0ca7fa5215b5cddc6d4ffd24bb7e6026e9 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 28 Jan 2021 18:24:58 +0100 Subject: [PATCH 48/50] added override to LESolver --- .../IterativeMinMaxLinearEquationSolver.cpp | 234 +++++++++--------- 1 file changed, 120 insertions(+), 114 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 5e71c0503..09bd57726 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -5,6 +5,7 @@ #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/OviSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/utility/ConstantsComparator.h" #include "storm/utility/KwekMehlhorn.h" @@ -19,27 +20,27 @@ namespace storm { namespace solver { - + template IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty } - + template IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(A), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } - + template IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A)), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } - + template MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environment const& env, bool isExactMode) const { // Adjust the method if none was specified and we want exact or sound computations. auto method = env.solver().minMax().getMethod(); - + if (isExactMode && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch && method != MinMaxMethod::ViToPi) { if (env.solver().minMax().isMethodSetFromDefault()) { STORM_LOG_INFO("Selecting 'Policy iteration' as the solution technique to guarantee exact results. If you want to override this, please explicitly specify a different method."); @@ -58,7 +59,7 @@ namespace storm { STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::OptimisticValueIteration || method == MinMaxMethod::ViToPi, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); return method; } - + template bool IterativeMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { bool result = false; @@ -87,14 +88,14 @@ namespace storm { default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); } - + return result; } template bool IterativeMinMaxLinearEquationSolver::solveInducedEquationSystem(Environment const& env, std::unique_ptr>& linearEquationSolver, std::vector const& scheduler, std::vector& x, std::vector& subB, std::vector const& originalB) const { assert(subB.size() == x.size()); - + // Resolve the nondeterminism according to the given scheduler. bool convertToEquationSystem = this->linearEquationSolverFactory->getEquationProblemFormat(env) == LinearEquationSolverProblemFormat::EquationSystem; storm::storage::SparseMatrix submatrix = this->A->selectRowsFromRowGroups(scheduler, convertToEquationSystem); @@ -102,7 +103,7 @@ namespace storm { submatrix.convertToEquationSystem(); } storm::utility::vector::selectVectorValues(subB, scheduler, this->A->getRowGroupIndices(), originalB); - + // Check whether the linear equation solver is already initialized if (!linearEquationSolver) { // Initialize the equation solver @@ -116,14 +117,14 @@ namespace storm { // Solve the equation system for the 'DTMC' and return true upon success return linearEquationSolver->solveEquations(env, x, subB); } - + template bool IterativeMinMaxLinearEquationSolver::solveEquationsPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Create the initial scheduler. std::vector scheduler = this->hasInitialScheduler() ? this->getInitialScheduler() : std::vector(this->A->getRowGroupCount()); return performPolicyIteration(env, dir, x, b, std::move(scheduler)); } - + template bool IterativeMinMaxLinearEquationSolver::performPolicyIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b, std::vector&& initialPolicy) const { std::vector scheduler = std::move(initialPolicy); @@ -162,7 +163,7 @@ namespace storm { do { // Solve the equation system for the 'DTMC'. solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b); - + // Go through the multiplication result and see whether we can improve any of the choices. bool schedulerImproved = false; for (uint_fast64_t group = 0; group < this->A->getRowGroupCount(); ++group) { @@ -172,14 +173,14 @@ namespace storm { if (choice - this->A->getRowGroupIndices()[group] == currentChoice) { continue; } - + // Create the value of the choice. ValueType choiceValue = storm::utility::zero(); for (auto const& entry : this->A->getRow(choice)) { choiceValue += entry.getValue() * x[entry.getColumn()]; } choiceValue += b[choice]; - + // If the value is strictly better than the solution of the inner system, we need to improve the scheduler. // TODO: If the underlying solver is not precise, this might run forever (i.e. when a state has two choices where the (exact) values are equal). // only changing the scheduler if the values are not equal (modulo precision) would make this unsound. @@ -190,12 +191,12 @@ namespace storm { } } } - + // If the scheduler did not improve, we are done. if (!schedulerImproved) { status = SolverStatus::Converged; } - + // Update environment variables. ++iterations; status = this->updateStatus(status, x, dir == storm::OptimizationDirection::Minimize ? SolverGuarantee::GreaterOrEqual : SolverGuarantee::LessOrEqual, iterations, env.solver().minMax().getMaximalNumberOfIterations()); @@ -203,21 +204,21 @@ namespace storm { // Potentially show progress. this->showProgressIterative(iterations); } while (status == SolverStatus::InProgress); - + this->reportStatus(status, iterations); - + // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::move(scheduler); } - + if (!this->isCachingEnabled()) { clearCache(); } return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; } - + template bool IterativeMinMaxLinearEquationSolver::valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const { if (dir == OptimizationDirection::Minimize) { @@ -230,7 +231,7 @@ namespace storm { template MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { auto method = getMethod(env, storm::NumberTraits::IsExact || env.solver().isForceExact()); - + // Check whether a linear equation solver is needed and potentially start with its requirements bool needsLinEqSolver = false; needsLinEqSolver |= method == MinMaxMethod::PolicyIteration; @@ -259,7 +260,7 @@ namespace storm { requirements.requireUniqueSolution(); } requirements.requireLowerBounds(); - + } else if (method == MinMaxMethod::IntervalIteration) { // Interval iteration requires a unique solution and lower+upper bounds if (!this->hasUniqueSolution()) { @@ -296,18 +297,18 @@ namespace storm { template typename IterativeMinMaxLinearEquationSolver::ValueIterationResult IterativeMinMaxLinearEquationSolver::performValueIteration(Environment const& env, OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { - + STORM_LOG_ASSERT(currentX != newX, "Vectors must not be aliased."); - + // Get handle to multiplier. storm::solver::Multiplier const& multiplier = *this->multiplierA; - + // Allow aliased multiplications. bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; - + // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = currentIterations; - + SolverStatus status = SolverStatus::InProgress; while (status == SolverStatus::InProgress) { // Compute x' = min/max(A*x + b). @@ -318,12 +319,12 @@ namespace storm { } else { multiplier.multiplyAndReduce(env, dir, *currentX, &b, *newX); } - + // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { status = SolverStatus::Converged; } - + // Update environment variables. std::swap(currentX, newX); ++iterations; @@ -332,7 +333,7 @@ namespace storm { // Potentially show progress. this->showProgressIterative(iterations); } - + return ValueIterationResult(iterations - currentIterations, status); } @@ -367,7 +368,7 @@ namespace storm { } return true; } - + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } @@ -376,14 +377,14 @@ namespace storm { } storm::solver::helper::OptimisticValueIterationHelper helper(*this->A); - + // x has to start with a lower bound. this->createLowerBoundsVector(x); std::vector* lowerX = &x; std::vector* upperX = auxiliaryRowGroupVector.get(); - + auto statusIters = helper.solveEquations(env, lowerX, upperX, b, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), @@ -413,14 +414,19 @@ namespace storm { if (!this->multiplierA) { this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } - + + // TODO cleanup + if(env.solver().multiplier().getOptimizationDirectionOverride().is_initialized()) { + multiplierA->setOptimizationDirectionOverride(env.solver().multiplier().getOptimizationDirectionOverride().get()); + } + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } - + // By default, we can not provide any guarantee SolverGuarantee guarantee = SolverGuarantee::None; - + if (this->hasInitialScheduler()) { // Solve the equation system induced by the initial scheduler. std::unique_ptr> linEqSolver; @@ -469,7 +475,7 @@ namespace storm { std::vector* newX = auxiliaryRowGroupVector.get(); std::vector* currentX = &x; - + this->startMeasureProgress(); ValueIterationResult result = performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(env.solver().minMax().getPrecision()), env.solver().minMax().getRelativeTerminationCriterion(), guarantee, 0, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); @@ -477,27 +483,27 @@ namespace storm { if (currentX == auxiliaryRowGroupVector.get()) { std::swap(x, *currentX); } - + this->reportStatus(result.status, result.iterations); - + // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); this->multiplierA->multiplyAndReduce(env, dir, x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); } - + if (!this->isCachingEnabled()) { clearCache(); } - + return result.status == SolverStatus::Converged || result.status == SolverStatus::TerminatedEarly; } - + template void preserveOldRelevantValues(std::vector const& allValues, storm::storage::BitVector const& relevantValues, std::vector& oldValues) { storm::utility::vector::selectVectorValues(oldValues, relevantValues, allValues); } - + /*! * This version of value iteration is sound, because it approaches the solution from below and above. This * technique is due to Haddad and Monmege (Interval iteration algorithm for MDPs and IMDPs, TCS 2017) and was @@ -511,28 +517,28 @@ namespace storm { if (!this->multiplierA) { this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } - + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } - + // Allow aliased multiplications. bool useGaussSeidelMultiplication = env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; - + std::vector* lowerX = &x; this->createLowerBoundsVector(*lowerX); this->createUpperBoundsVector(this->auxiliaryRowGroupVector, this->A->getRowGroupCount()); std::vector* upperX = this->auxiliaryRowGroupVector.get(); - + std::vector* tmp = nullptr; if (!useGaussSeidelMultiplication) { auxiliaryRowGroupVector2 = std::make_unique>(lowerX->size()); tmp = auxiliaryRowGroupVector2.get(); } - + // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = 0; - + SolverStatus status = SolverStatus::InProgress; bool doConvergenceCheck = true; bool useDiffs = this->hasRelevantValues() && !env.solver().minMax().isSymmetricUpdatesSet(); @@ -636,7 +642,7 @@ namespace storm { status = storm::utility::vector::equalModuloPrecision(*lowerX, *upperX, precision, relative) ? SolverStatus::Converged : status; } } - + // Update environment variables. ++iterations; doConvergenceCheck = !doConvergenceCheck; @@ -650,33 +656,33 @@ namespace storm { // Potentially show progress. this->showProgressIterative(iterations); } - + this->reportStatus(status, iterations); // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); - + // Since we shuffled the pointer around, we need to write the actual results to the input/output vector x. if (&x == tmp) { std::swap(x, *tmp); } else if (&x == this->auxiliaryRowGroupVector.get()) { std::swap(x, *this->auxiliaryRowGroupVector); } - + // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); this->multiplierA->multiplyAndReduce(env, dir, x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); } - + if (!this->isCachingEnabled()) { clearCache(); } - + return status == SolverStatus::Converged; } - + template bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { @@ -690,7 +696,7 @@ namespace storm { } else { this->soundValueIterationHelper = std::make_unique>(std::move(*this->soundValueIterationHelper), x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); } - + // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { this->soundValueIterationHelper->setLowerBound(this->getLowerBound(true)); @@ -698,16 +704,16 @@ namespace storm { if (this->hasUpperBound()) { this->soundValueIterationHelper->setUpperBound(this->getUpperBound(true)); } - + storm::storage::BitVector const* relevantValuesPtr = nullptr; if (this->hasRelevantValues()) { relevantValuesPtr = &this->getRelevantValues(); } - + SolverStatus status = SolverStatus::InProgress; this->startMeasureProgress(); uint64_t iterations = 0; - + while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { ++iterations; this->soundValueIterationHelper->performIterationStep(dir, b); @@ -716,12 +722,12 @@ namespace storm { } else { status = this->updateStatus(status, this->hasCustomTerminationCondition() && this->soundValueIterationHelper->checkCustomTerminationCondition(this->getTerminationCondition()), iterations, env.solver().minMax().getMaximalNumberOfIterations()); } - + // Potentially show progress. this->showProgressIterative(iterations); } this->soundValueIterationHelper->setSolutionVector(); - + // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); @@ -729,14 +735,14 @@ namespace storm { } this->reportStatus(status, iterations); - + if (!this->isCachingEnabled()) { clearCache(); } - + return status == SolverStatus::Converged; } - + template bool IterativeMinMaxLinearEquationSolver::solveEquationsViToPi(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // First create an (inprecise) vi solver to get a good initial strategy for the (potentially precise) policy iteration solver. @@ -760,11 +766,11 @@ namespace storm { STORM_LOG_INFO("Found initial policy using Value Iteration. Starting Policy iteration now."); return performPolicyIteration(env, dir, x, b, std::move(initialSched)); } - + template bool IterativeMinMaxLinearEquationSolver::isSolution(storm::OptimizationDirection dir, storm::storage::SparseMatrix const& matrix, std::vector const& values, std::vector const& b) { storm::utility::ConstantsComparator comparator; - + auto valueIt = values.begin(); auto bIt = b.begin(); for (uint64_t group = 0; group < matrix.getRowGroupCount(); ++group, ++valueIt) { @@ -778,18 +784,18 @@ namespace storm { for (auto endRow = matrix.getRowGroupIndices()[group + 1]; row < endRow; ++row, ++bIt) { ValueType newValue = *bIt; newValue += matrix.multiplyRowWithVector(row, values); - + if ((dir == storm::OptimizationDirection::Minimize && newValue < groupValue) || (dir == storm::OptimizationDirection::Maximize && newValue > groupValue)) { groupValue = newValue; } } - + // If the value does not match the one in the values vector, the given vector is not a solution. if (!comparator.isEqual(groupValue, *valueIt)) { return false; } } - + // Checked all values at this point. return true; } @@ -797,7 +803,7 @@ namespace storm { template template bool IterativeMinMaxLinearEquationSolver::sharpen(storm::OptimizationDirection dir, uint64_t precision, storm::storage::SparseMatrix const& A, std::vector const& x, std::vector const& b, std::vector& tmp) { - + for (uint64_t p = 0; p <= precision; ++p) { storm::utility::kwek_mehlhorn::sharpen(p, x, tmp); @@ -817,18 +823,18 @@ namespace storm { storm::storage::SparseMatrix rationalA = this->A->template toValueType(); std::vector rationalX(x.size()); std::vector rationalB = storm::utility::vector::convertNumericVector(b); - + if (!this->multiplierA) { this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } - + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } - + // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, dir, *this, rationalA, rationalX, rationalB, *this->A, x, b, *auxiliaryRowGroupVector); - + // Translate back rational result to imprecise result. auto targetIt = x.begin(); for (auto it = rationalX.begin(), ite = rationalX.end(); it != ite; ++it, ++targetIt) { @@ -838,30 +844,30 @@ namespace storm { if (!this->isCachingEnabled()) { this->clearCache(); } - + return converged; } - + template template typename std::enable_if::value && NumberTraits::IsExact, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the same type is to be used for the imprecise part. - + if (!this->multiplierA) { this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } - + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } - + // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, dir, *this, *this->A, x, b, *this->A, *auxiliaryRowGroupVector, b, x); if (!this->isCachingEnabled()) { this->clearCache(); } - + return converged; } @@ -870,10 +876,10 @@ namespace storm { typename std::enable_if::value, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the imprecise one is not. We first try to solve the // problem using the imprecise data type and fall back to the exact type as needed. - + // Translate A to its imprecise version. storm::storage::SparseMatrix impreciseA = this->A->template toValueType(); - + // Translate x to its imprecise version. std::vector impreciseX(x.size()); { @@ -884,23 +890,23 @@ namespace storm { *targetIt = storm::utility::convertNumber(*sourceIt); } } - + // Create temporary storage for an imprecise x. std::vector impreciseTmpX(x.size()); - + // Translate b to its imprecise version. std::vector impreciseB(b.size()); auto targetIt = impreciseB.begin(); for (auto sourceIt = b.begin(); targetIt != impreciseB.end(); ++targetIt, ++sourceIt) { *targetIt = storm::utility::convertNumber(*sourceIt); } - + // Create imprecise solver from the imprecise data. IterativeMinMaxLinearEquationSolver impreciseSolver(std::make_unique>()); impreciseSolver.setMatrix(impreciseA); impreciseSolver.setCachingEnabled(true); impreciseSolver.multiplierA = storm::solver::MultiplierFactory().create(env, impreciseA); - + bool converged = false; try { // Forward the call to the core rational search routine. @@ -908,7 +914,7 @@ namespace storm { impreciseSolver.clearCache(); } catch (storm::exceptions::PrecisionExceededException const& e) { STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic."); - + if (!auxiliaryRowGroupVector) { auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); } @@ -918,7 +924,7 @@ namespace storm { for (auto it = impreciseX.begin(), ite = impreciseX.end(); it != ite; ++it, ++targetIt) { *targetIt = storm::utility::convertNumber(*it); } - + // Get rid of the superfluous data structures. impreciseX = std::vector(); impreciseTmpX = std::vector(); @@ -928,15 +934,15 @@ namespace storm { if (!this->multiplierA) { this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } - + // Forward the call to the core rational search routine, but now with our value type as the imprecise value type. converged = solveEquationsRationalSearchHelper(env, dir, *this, *this->A, x, b, *this->A, *auxiliaryRowGroupVector, b, x); } - + if (!this->isCachingEnabled()) { this->clearCache(); } - + return converged; } @@ -945,12 +951,12 @@ namespace storm { static std::vector* getTemporary(std::vector& rationalX, std::vector*& currentX, std::vector*& newX) { return &rationalX; } - + static void swapSolutions(std::vector& rationalX, std::vector*& rationalSolution, std::vector& x, std::vector*& currentX, std::vector*& newX) { // Nothing to do. } }; - + template struct TemporaryHelper { static std::vector* getTemporary(std::vector& rationalX, std::vector*& currentX, std::vector*& newX) { @@ -960,7 +966,7 @@ namespace storm { static void swapSolutions(std::vector& rationalX, std::vector*& rationalSolution, std::vector& x, std::vector*& currentX, std::vector*& newX) { if (&rationalX == rationalSolution) { // In this case, the rational solution is in place. - + // However, since the rational solution is no alias to current x, the imprecise solution is stored // in current x and and rational x is not an alias to x, we can swap the contents of currentX to x. std::swap(x, *currentX); @@ -971,7 +977,7 @@ namespace storm { } } }; - + template template bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, IterativeMinMaxLinearEquationSolver const& impreciseSolver, storm::storage::SparseMatrix const& rationalA, std::vector& rationalX, std::vector const& rationalB, storm::storage::SparseMatrix const& A, std::vector& x, std::vector const& b, std::vector& tmpX) const { @@ -989,29 +995,29 @@ namespace storm { while (status == SolverStatus::InProgress && overallIterations < env.solver().minMax().getMaximalNumberOfIterations()) { // Perform value iteration with the current precision. typename IterativeMinMaxLinearEquationSolver::ValueIterationResult result = impreciseSolver.performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(precision), env.solver().minMax().getRelativeTerminationCriterion(), SolverGuarantee::LessOrEqual, overallIterations, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); - + // At this point, the result of the imprecise value iteration is stored in the (imprecise) current x. - + ++valueIterationInvocations; STORM_LOG_TRACE("Completed " << valueIterationInvocations << " value iteration invocations, the last one with precision " << precision << " completed in " << result.iterations << " iterations."); - + // Count the iterations. overallIterations += result.iterations; - + // Compute maximal precision until which to sharpen. uint64_t p = storm::utility::convertNumber(storm::utility::ceil(storm::utility::log10(storm::utility::one() / precision))); - + // Make sure that currentX and rationalX are not aliased. std::vector* temporaryRational = TemporaryHelper::getTemporary(rationalX, currentX, newX); - + // Sharpen solution and place it in the temporary rational. bool foundSolution = sharpen(dir, p, rationalA, *currentX, rationalB, *temporaryRational); - + // After sharpen, if a solution was found, it is contained in the free rational. - + if (foundSolution) { status = SolverStatus::Converged; - + TemporaryHelper::swapSolutions(rationalX, temporaryRational, x, currentX, newX); } else { // Increase the precision. @@ -1020,14 +1026,14 @@ namespace storm { status = this->updateStatus(status, false, overallIterations, env.solver().minMax().getMaximalNumberOfIterations()); } - + // Swap the two vectors if the current result is not in the original x. if (currentX != originalX) { std::swap(x, tmpX); } - + this->reportStatus(status, overallIterations); - + return status == SolverStatus::Converged || status == SolverStatus::TerminatedEarly; } @@ -1035,18 +1041,18 @@ namespace storm { bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { return solveEquationsRationalSearchHelper(env, dir, x, b); } - + template void IterativeMinMaxLinearEquationSolver::computeOptimalValueForRowGroup(uint_fast64_t group, OptimizationDirection dir, std::vector& x, std::vector const& b, uint_fast64_t* choice) const { uint64_t row = this->A->getRowGroupIndices()[group]; uint64_t groupEnd = this->A->getRowGroupIndices()[group + 1]; assert(row != groupEnd); - + auto bIt = b.begin() + row; ValueType& xi = x[group]; xi = this->A->multiplyRowWithVector(row, x) + *bIt; uint64_t optimalRow = row; - + for (++row, ++bIt; row < groupEnd; ++row, ++bIt) { ValueType choiceVal = this->A->multiplyRowWithVector(row, x) + *bIt; if (minimize(dir)) { @@ -1065,7 +1071,7 @@ namespace storm { *choice = optimalRow - this->A->getRowGroupIndices()[group]; } } - + template void IterativeMinMaxLinearEquationSolver::clearCache() const { multiplierA.reset(); @@ -1075,9 +1081,9 @@ namespace storm { optimisticValueIterationHelper.reset(); StandardMinMaxLinearEquationSolver::clearCache(); } - + template class IterativeMinMaxLinearEquationSolver; - + #ifdef STORM_HAVE_CARL template class IterativeMinMaxLinearEquationSolver; #endif From 2a88a3e95f9c0b06001b5cbf02e40b6d1e007519 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 28 Jan 2021 18:26:06 +0100 Subject: [PATCH 49/50] fix backwards multiplier --- src/storm/solver/GmmxxMultiplier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index a6c64bfa5..19801a28e 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -179,7 +179,7 @@ namespace storm { uint64_t selectedChoice; uint64_t currentRow = backwards ? gmmMatrix.nrows() - 1 : 0; - uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 1 : 0; + uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 2 : 0; auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin(); auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1; if(choices) STORM_LOG_DEBUG(" "); From 4c1b0d77f6e39f19c0ec0447918adcedbd6920c0 Mon Sep 17 00:00:00 2001 From: Stefan Pranger Date: Thu, 28 Jan 2021 18:27:16 +0100 Subject: [PATCH 50/50] init rpatl mc and helper This - adds a temporary GameViHelper, needs refactoring in the future - additional methods to rpatlMC and an - rpatl helper. --- .../rpatl/SparseSmgRpatlModelChecker.cpp | 81 +++---- .../rpatl/SparseSmgRpatlModelChecker.h | 4 + .../rpatl/helper/SparseSmgRpatlHelper.cpp | 97 +++++++++ .../rpatl/helper/SparseSmgRpatlHelper.h | 47 +++++ .../rpatl/helper/internal/GameViHelper.cpp | 198 ++++++++++++++++++ .../rpatl/helper/internal/GameViHelper.h | 77 +++++++ 6 files changed, 466 insertions(+), 38 deletions(-) create mode 100644 src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp create mode 100644 src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.h create mode 100644 src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp create mode 100644 src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp index 35464513d..e3f5d46fd 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp @@ -12,6 +12,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h" +#include "storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.h" #include "storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h" #include "storm/modelchecker/helper/utility/SetInformationFromCheckTask.h" @@ -54,8 +55,6 @@ namespace storm { } } - - template std::unique_ptr SparseSmgRpatlModelChecker::checkGameFormula(Environment const& env, CheckTask const& checkTask) { Environment solverEnv = env; @@ -69,10 +68,25 @@ namespace storm { return this->checkRewardOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asRewardOperatorFormula())); } else if (subFormula.isLongRunAverageOperatorFormula()) { return this->checkLongRunAverageOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula())); + } else if (subFormula.isProbabilityOperatorFormula()) { + return this->checkProbabilityOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asProbabilityOperatorFormula())); } STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Cannot check this property (yet)."); } + template + std::unique_ptr SparseSmgRpatlModelChecker::checkProbabilityOperatorFormula(Environment const& env, CheckTask const& checkTask) { + storm::logic::ProbabilityOperatorFormula const& stateFormula = checkTask.getFormula(); + std::unique_ptr result = this->computeProbabilities(env, checkTask.substituteFormula(stateFormula.getSubformula())); + + if (checkTask.isBoundSet()) { + STORM_LOG_THROW(result->isQuantitative(), storm::exceptions::InvalidOperationException, "Unable to perform comparison operation on non-quantitative result."); + return result->asQuantitativeCheckResult().compareAgainstBound(checkTask.getBoundComparisonType(), checkTask.getBoundThreshold()); + } else { + return result; + } + } + template std::unique_ptr SparseSmgRpatlModelChecker::checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) { storm::logic::RewardOperatorFormula const& formula = checkTask.getFormula(); @@ -89,7 +103,14 @@ namespace storm { return result; } - + template + std::unique_ptr SparseSmgRpatlModelChecker::computeProbabilities(Environment const& env, CheckTask const& checkTask) { + storm::logic::Formula const& formula = checkTask.getFormula(); + if (formula.isReachabilityProbabilityFormula()) { + return this->computeReachabilityProbabilities(env, checkTask.substituteFormula(formula.asReachabilityProbabilityFormula())); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid."); + } template std::unique_ptr SparseSmgRpatlModelChecker::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { @@ -100,6 +121,25 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' cannot (yet) be handled."); } + template + std::unique_ptr SparseSmgRpatlModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { + // Currently we only support computation of reachability probabilities, i.e. the left subformula will always be 'true' (for now). + storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr leftResultPointer = this->check(env, pathFormula.getLeftSubformula()); + std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); + ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); + ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); + storm::solver::SolveGoal foo(this->getModel(), checkTask); + + auto ret = storm::modelchecker::helper::SparseSmgRpatlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), statesOfCoalition, checkTask.isProduceSchedulersSet(), checkTask.getHint()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + if (checkTask.isProduceSchedulersSet() && ret.scheduler) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + } + return result; + } + template std::unique_ptr SparseSmgRpatlModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "NYI"); @@ -119,41 +159,6 @@ namespace storm { return result; } - - - //template - //void SparseSmgRpatlModelChecker::coalitionIndicator(Environment& env, CheckTask const& checkTask) { - // storm::storage::BitVector coalitionIndicators(this->getModel().getTransitionMatrix().getRowGroupCount()); - - // std::vector> formulaPlayerIds = checkTask.getFormula().getCoalition().getPlayers(); - // std::vector playerIds; - // std::vector> playerActionIndices = this->getModel().getStatePlayerIndications(); - - // for(auto const& player : formulaPlayerIds) { - // // If the player is given via the player name we have to look up its index - // if(player.type() == typeid(std::string)) { - // auto it = std::find_if(playerActionIndices.begin(), playerActionIndices.end(), - // [&player](const std::pair& element){ return element.first == boost::get(player); }); - // playerIds.push_back(it->second); - // // If the player is given by its index we have to shift it to match internal mappings - // } else if(player.type() == typeid(uint_fast64_t)) { - // playerIds.push_back(boost::get(player) - 1); - // } - // } - // //for(auto const& p : playerActionIndices) std::cout << p.first << " - " << p.second << ", "; std::cout << std::endl; - // //for(auto const& p : playerIds) std::cout << p << ", "; std::cout << std::endl; - - // for(uint i = 0; i < playerActionIndices.size(); i++) { - // if(std::find(playerIds.begin(), playerIds.end(), playerActionIndices.at(i).second) != playerIds.end()) { - // coalitionIndicators.set(i); - // } - // } - // coalitionIndicators.complement(); - - // //std::cout << "MINMAX OVERRIDE: " << coalitionIndicators << std::endl; - // env.solver().multiplier().setOptimizationDirectionOverride(coalitionIndicators); - //} - template class SparseSmgRpatlModelChecker>; #ifdef STORM_HAVE_CARL template class SparseSmgRpatlModelChecker>; diff --git a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h index 9f5889caf..dfbd47762 100644 --- a/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h +++ b/src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.h @@ -29,10 +29,14 @@ namespace storm { // The implemented methods of the AbstractModelChecker interface. bool canHandle(CheckTask const& checkTask) const override; std::unique_ptr checkGameFormula(Environment const& env, CheckTask const& checkTask) override; + std::unique_ptr checkProbabilityOperatorFormula(Environment const& env, CheckTask const& checkTask) override; std::unique_ptr checkRewardOperatorFormula(Environment const& env, CheckTask const& checkTask) override; std::unique_ptr checkLongRunAverageOperatorFormula(Environment const& env, CheckTask const& checkTask) override; + std::unique_ptr computeProbabilities(Environment const& env, CheckTask const& checkTask) override; std::unique_ptr computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + + std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; diff --git a/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp b/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp new file mode 100644 index 000000000..9bf5a10e8 --- /dev/null +++ b/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.cpp @@ -0,0 +1,97 @@ +#include "SparseSmgRpatlHelper.h" + +#include "storm/environment/Environment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/utility/vector.h" + +#include "storm/modelchecker/rpatl/helper/internal/GameViHelper.h" + + +namespace storm { + namespace modelchecker { + namespace helper { + + template + MDPSparseModelCheckingHelperReturnType SparseSmgRpatlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::storage::BitVector statesOfCoalition, bool produceScheduler, ModelCheckerHint const& hint) { + // TODO add Kwiatkowska original reference + // TODO FIX solver min max mess + + auto solverEnv = env; + solverEnv.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration, false); + + // Initialize the solution vector. + std::vector x = std::vector(transitionMatrix.getRowGroupCount() - psiStates.getNumberOfSetBits(), storm::utility::zero()); + std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(~psiStates, psiStates); + + // Reduce matrix to ~Prob1 states- + //STORM_LOG_DEBUG("\n" << transitionMatrix); + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, ~psiStates, ~psiStates, false); + //STORM_LOG_DEBUG("\n" << submatrix); + + + //STORM_LOG_DEBUG("x = " << storm::utility::vector::toString(x)); + //STORM_LOG_DEBUG("b = " << storm::utility::vector::toString(b)); + + storm::storage::BitVector clippedStatesOfCoalition(statesOfCoalition.size() - psiStates.getNumberOfSetBits()); + //STORM_LOG_DEBUG(psiStates); + //STORM_LOG_DEBUG(statesOfCoalition); + //STORM_LOG_DEBUG(clippedStatesOfCoalition); + + // TODO move this to BitVector-class + auto clippedStatesCounter = 0; + for(uint i = 0; i < psiStates.size(); i++) { + std::cout << i << " : " << psiStates.get(i) << " -> " << statesOfCoalition[i] << std::endl; + if(!psiStates.get(i)) { + clippedStatesOfCoalition.set(clippedStatesCounter, statesOfCoalition[i]); + clippedStatesCounter++; + } + } + //STORM_LOG_DEBUG(clippedStatesOfCoalition); + clippedStatesOfCoalition.complement(); + //STORM_LOG_DEBUG(clippedStatesOfCoalition); + + storm::modelchecker::helper::internal::GameViHelper viHelper(submatrix, clippedStatesOfCoalition); + std::unique_ptr> scheduler; + if (produceScheduler) { + viHelper.setProduceScheduler(true); + } + + viHelper.performValueIteration(env, x, b, goal.direction()); + + STORM_LOG_DEBUG(storm::utility::vector::toString(x)); + if (produceScheduler) { + scheduler = std::make_unique>(expandScheduler(viHelper.extractScheduler(), psiStates)); + STORM_LOG_DEBUG("IsPartial?" << scheduler->isPartialScheduler()); + } + return MDPSparseModelCheckingHelperReturnType(std::move(x), std::move(scheduler)); + } + + template + storm::storage::Scheduler SparseSmgRpatlHelper::expandScheduler(storm::storage::Scheduler scheduler, storm::storage::BitVector psiStates) { + //STORM_LOG_DEBUG(psiStates.size()); + for(uint i = 0; i < 2; i++) { + //STORM_LOG_DEBUG(scheduler.getChoice(i)); + } + storm::storage::Scheduler completeScheduler(psiStates.size()); + uint_fast64_t maybeStatesCounter = 0; + for(uint stateCounter = 0; stateCounter < psiStates.size(); stateCounter++) { + //STORM_LOG_DEBUG(stateCounter << " : " << psiStates.get(stateCounter)); + if(psiStates.get(stateCounter)) { + completeScheduler.setChoice(0, stateCounter); + } else { + completeScheduler.setChoice(scheduler.getChoice(maybeStatesCounter), stateCounter); + maybeStatesCounter++; + } + } + return completeScheduler; + } + + template class SparseSmgRpatlHelper; +#ifdef STORM_HAVE_CARL + template class SparseSmgRpatlHelper; +#endif + } + } +} diff --git a/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.h b/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.h new file mode 100644 index 000000000..9505bd51f --- /dev/null +++ b/src/storm/modelchecker/rpatl/helper/SparseSmgRpatlHelper.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "storm/modelchecker/hints/ModelCheckerHint.h" +#include "storm/modelchecker/prctl/helper/SolutionType.h" +#include "storm/storage/SparseMatrix.h" + +#include "storm/utility/solver.h" +#include "storm/solver/SolveGoal.h" + +#include "storm/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h" + +namespace storm { + + class Environment; + + namespace storage { + class BitVector; + } + + namespace models { + namespace sparse { + template + class StandardRewardModel; + } + } + + namespace modelchecker { + class CheckResult; + + namespace helper { + + template + class SparseSmgRpatlHelper { + public: + // TODO should probably be renamed in the future: + + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::storage::BitVector statesOfCoalition, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + + private: + static storm::storage::Scheduler expandScheduler(storm::storage::Scheduler scheduler, storm::storage::BitVector psiStates); + + }; + } + } +} diff --git a/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp b/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp new file mode 100644 index 000000000..4f6fc1e4e --- /dev/null +++ b/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.cpp @@ -0,0 +1,198 @@ +#include "GameViHelper.h" + +#include "storm/environment/Environment.h" +#include "storm/environment/solver/SolverEnvironment.h" +#include "storm/environment/solver/GameSolverEnvironment.h" + + +#include "storm/utility/SignalHandler.h" +#include "storm/utility/vector.h" + +// TODO this will undergo major refactoring as soon as we implement model checking of further properties + +namespace storm { + namespace modelchecker { + namespace helper { + namespace internal { + + template + GameViHelper::GameViHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector statesOfCoalition) : _transitionMatrix(transitionMatrix), _statesOfCoalition(statesOfCoalition) { + } + + template + void GameViHelper::prepareSolversAndMultipliersReachability(const Environment& env) { + // TODO we get whole transitionmatrix and psistates DONE IN smgrpatlhelper + // -> clip statesofcoalition + // -> compute b vector from psiStates + // -> clip transitionmatrix and create multiplier + _multiplier = storm::solver::MultiplierFactory().create(env, _transitionMatrix); + _multiplier->setOptimizationDirectionOverride(_statesOfCoalition); + + _x1IsCurrent = false; + } + + template + void GameViHelper::performValueIteration(Environment const& env, std::vector& x, std::vector b, storm::solver::OptimizationDirection const dir) { + prepareSolversAndMultipliersReachability(env); + ValueType precision = storm::utility::convertNumber(env.solver().game().getPrecision()); + uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); + _b = b; + + _x1.assign(_transitionMatrix.getRowGroupCount(), storm::utility::zero()); + _x2 = _x1; + + if (this->isProduceSchedulerSet()) { + if (!this->_producedOptimalChoices.is_initialized()) { + this->_producedOptimalChoices.emplace(); + } + this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount()); + } + + uint64_t iter = 0; + std::vector result = x; + while (iter < maxIter) { + ++iter; + performIterationStep(env, dir); + + if (checkConvergence(precision)) { + break; + } + if (storm::utility::resources::isTerminate()) { + break; + } + } + x = xNew(); + + if (isProduceSchedulerSet()) { + // We will be doing one more iteration step and track scheduler choices this time. + performIterationStep(env, dir, &_producedOptimalChoices.get()); + } + } + + template + void GameViHelper::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const dir, std::vector* choices) { + if (!_multiplier) { + prepareSolversAndMultipliersReachability(env); + } + _x1IsCurrent = !_x1IsCurrent; + + // multiplyandreducegaussseidel + // Ax + b + if (choices == nullptr) { + //STORM_LOG_DEBUG("\n" << _transitionMatrix); + //STORM_LOG_DEBUG("xOld = " << storm::utility::vector::toString(xOld())); + //STORM_LOG_DEBUG("b = " << storm::utility::vector::toString(_b)); + //STORM_LOG_DEBUG("xNew = " << storm::utility::vector::toString(xNew())); + _multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew()); + //std::cin.get(); + } else { + // Also keep track of the choices made. + _multiplier->multiplyAndReduce(env, dir, xOld(), &_b, xNew(), choices); + } + + // compare applyPointwise + storm::utility::vector::applyPointwise(xOld(), xNew(), xNew(), [&dir] (ValueType const& a, ValueType const& b) -> ValueType { + if(storm::solver::maximize(dir)) { + if(a > b) return a; + else return b; + } else { + if(a > b) return a; + else return b; + } + }); + } + + template + bool GameViHelper::checkConvergence(ValueType threshold) const { + STORM_LOG_ASSERT(_multiplier, "tried to check for convergence without doing an iteration first."); + + // Now check whether the currently produced results are precise enough + STORM_LOG_ASSERT(threshold > storm::utility::zero(), "Did not expect a non-positive threshold."); + auto x1It = xOld().begin(); + auto x1Ite = xOld().end(); + auto x2It = xNew().begin(); + ValueType maxDiff = (*x2It - *x1It); + ValueType minDiff = maxDiff; + // The difference between maxDiff and minDiff is zero at this point. Thus, it doesn't make sense to check the threshold now. + for (++x1It, ++x2It; x1It != x1Ite; ++x1It, ++x2It) { + ValueType diff = (*x2It - *x1It); + // Potentially update maxDiff or minDiff + bool skipCheck = false; + if (maxDiff < diff) { + maxDiff = diff; + } else if (minDiff > diff) { + minDiff = diff; + } else { + skipCheck = true; + } + // Check convergence + if (!skipCheck && (maxDiff - minDiff) > threshold) { + return false; + } + } + // TODO needs checking + return true; + } + + template + void GameViHelper::setProduceScheduler(bool value) { + _produceScheduler = value; + } + + template + bool GameViHelper::isProduceSchedulerSet() const { + return _produceScheduler; + } + + template + std::vector const& GameViHelper::getProducedOptimalChoices() const { + 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?"); + return this->_producedOptimalChoices.get(); + } + + template + std::vector& GameViHelper::getProducedOptimalChoices() { + 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?"); + return this->_producedOptimalChoices.get(); + } + + template + storm::storage::Scheduler GameViHelper::extractScheduler() const{ + auto const& optimalChoices = getProducedOptimalChoices(); + storm::storage::Scheduler scheduler(optimalChoices.size()); + for (uint64_t state = 0; state < optimalChoices.size(); ++state) { + scheduler.setChoice(optimalChoices[state], state); + } + return scheduler; + } + + template + std::vector& GameViHelper::xNew() { + return _x1IsCurrent ? _x1 : _x2; + } + + template + std::vector const& GameViHelper::xNew() const { + return _x1IsCurrent ? _x1 : _x2; + } + + template + std::vector& GameViHelper::xOld() { + return _x1IsCurrent ? _x2 : _x1; + } + + template + std::vector const& GameViHelper::xOld() const { + return _x1IsCurrent ? _x2 : _x1; + } + + template class GameViHelper; +#ifdef STORM_HAVE_CARL + template class GameViHelper; +#endif + } + } + } +} diff --git a/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h b/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h new file mode 100644 index 000000000..92f963851 --- /dev/null +++ b/src/storm/modelchecker/rpatl/helper/internal/GameViHelper.h @@ -0,0 +1,77 @@ +#pragma once + +#include "storm/storage/SparseMatrix.h" +#include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" + +namespace storm { + class Environment; + + namespace storage { + template class Scheduler; + } + + namespace modelchecker { + namespace helper { + namespace internal { + + template + class GameViHelper { + public: + GameViHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector statesOfCoalition); + + void prepareSolversAndMultipliersReachability(const Environment& env); + + void performValueIteration(Environment const& env, std::vector& x, std::vector b, storm::solver::OptimizationDirection const dir); + + /*h + * Sets whether an optimal scheduler shall be constructed during the computation + */ + void setProduceScheduler(bool value); + + /*! + * @return whether an optimal scheduler shall be constructed during the computation + */ + bool isProduceSchedulerSet() const; + + storm::storage::Scheduler extractScheduler() const; + private: + void performIterationStep(Environment const& env, storm::solver::OptimizationDirection const dir, std::vector* choices = nullptr); + + /*! + * Checks whether the curently computed value achieves the desired precision + */ + bool checkConvergence(ValueType precision) const; + + std::vector& xNew(); + std::vector const& xNew() const; + + std::vector& xOld(); + std::vector const& xOld() const; + bool _x1IsCurrent; + + /*! + * @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. + */ + std::vector const& getProducedOptimalChoices() const; + + /*! + * @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. + */ + std::vector& getProducedOptimalChoices(); + + storm::storage::SparseMatrix _transitionMatrix; + storm::storage::BitVector _statesOfCoalition; + std::vector _x1, _x2, _b; + std::unique_ptr> _multiplier; + + bool _produceScheduler = false; + boost::optional> _producedOptimalChoices; + }; + } + } + } +}