#include "HybridInfiniteHorizonHelper.h" #include "storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h" #include "storm/modelchecker/helper/infinitehorizon/SparseDeterministicInfiniteHorizonHelper.h" #include "storm/modelchecker/helper/utility/SetInformationFromOtherHelper.h" #include "storm/models/symbolic/NondeterministicModel.h" #include "storm/storage/SparseMatrix.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" namespace storm { namespace modelchecker { namespace helper { template HybridInfiniteHorizonHelper::HybridInfiniteHorizonHelper(storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix) : _model(model), _transitionMatrix(transitionMatrix), _markovianStates(nullptr), _exitRates(nullptr) { // Intentionally left empty. } template HybridInfiniteHorizonHelper::HybridInfiniteHorizonHelper(storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& markovianStates, storm::dd::Add const& exitRateVector) : _model(model), _transitionMatrix(transitionMatrix), _markovianStates(&markovianStates), _exitRates(&exitRateVector) { // Intentionally left empty. } template HybridInfiniteHorizonHelper::HybridInfiniteHorizonHelper(storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector) : _model(model), _transitionMatrix(transitionMatrix), _markovianStates(nullptr), _exitRates(&exitRateVector) { // Intentionally left empty. } template std::unique_ptr> HybridInfiniteHorizonHelper::computeLongRunAverageProbabilities(Environment const& env, storm::dd::Bdd const& psiStates) { // Convert this query to an instance for the sparse engine. // Create ODD for the translation. storm::dd::Odd odd = _model.getReachableStates().createOdd(); // Translate all required components storm::storage::SparseMatrix explicitTransitionMatrix; if (_model.isNondeterministicModel()) { explicitTransitionMatrix = _transitionMatrix.toMatrix(dynamic_cast const&>(_model).getNondeterminismVariables(), odd, odd); } else { explicitTransitionMatrix = _transitionMatrix.toMatrix(odd, odd); } std::vector explicitExitRateVector; storm::storage::BitVector explicitMarkovianStates; if (isContinuousTime()) { explicitExitRateVector = _exitRates->toVector(odd); if (_markovianStates) { explicitMarkovianStates = _markovianStates->toVector(odd); } } auto sparseHelper = createSparseHelper(explicitTransitionMatrix, explicitMarkovianStates, explicitExitRateVector, odd); auto explicitResult = sparseHelper->computeLongRunAverageProbabilities(env, psiStates.toVector(odd)); return std::make_unique>(_model.getReachableStates(), _model.getManager().getBddZero(), _model.getManager().template getAddZero(), _model.getReachableStates(), std::move(odd), std::move(explicitResult)); } template std::unique_ptr> HybridInfiniteHorizonHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::StandardRewardModel const& rewardModel) { // Convert this query to an instance for the sparse engine. // Create ODD for the translation. storm::dd::Odd odd = _model.getReachableStates().createOdd(); // Translate all required components // Transitions and rewards storm::storage::SparseMatrix explicitTransitionMatrix; std::vector explicitStateRewards, explicitActionRewards; if (rewardModel.hasStateRewards()) { explicitStateRewards = rewardModel.getStateRewardVector().toVector(odd); } if (_model.isNondeterministicModel() && rewardModel.hasStateActionRewards()) { // Matrix and action-based vector have to be produced at the same time to guarantee the correct order auto matrixRewards = _transitionMatrix.toMatrixVector(rewardModel.getStateActionRewardVector(), dynamic_cast const&>(_model).getNondeterminismVariables(), odd, odd); explicitTransitionMatrix = std::move(matrixRewards.first); explicitActionRewards = std::move(matrixRewards.second); } else { // Translate matrix only explicitTransitionMatrix = _transitionMatrix.toMatrix(dynamic_cast const&>(_model).getNondeterminismVariables(), odd, odd); if (rewardModel.hasStateActionRewards()) { // For deterministic models we can translate the action rewards easily explicitActionRewards = rewardModel.getStateActionRewardVector().toVector(odd); } } STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException, "Transition rewards are not supported in this engine."); // Continuous time information std::vector explicitExitRateVector; storm::storage::BitVector explicitMarkovianStates; if (isContinuousTime()) { explicitExitRateVector = _exitRates->toVector(odd); if (_markovianStates) { explicitMarkovianStates = _markovianStates->toVector(odd); } } auto sparseHelper = createSparseHelper(explicitTransitionMatrix, explicitMarkovianStates, explicitExitRateVector, odd); auto explicitResult = sparseHelper->computeLongRunAverageValues(env, rewardModel.hasStateRewards() ? &explicitStateRewards : nullptr, rewardModel.hasStateActionRewards() ? &explicitActionRewards : nullptr); return std::make_unique>(_model.getReachableStates(), _model.getManager().getBddZero(), _model.getManager().template getAddZero(), _model.getReachableStates(), std::move(odd), std::move(explicitResult)); } template bool HybridInfiniteHorizonHelper::isContinuousTime() const { STORM_LOG_ASSERT((_markovianStates == nullptr) || (_exitRates != nullptr), "Inconsistent information given: Have Markovian states but no exit rates." ); return _exitRates != nullptr; } template template > std::unique_ptr> HybridInfiniteHorizonHelper::createSparseHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector const& exitRates, storm::dd::Odd const& odd) const { std::unique_ptr> result; if (isContinuousTime()) { result = std::make_unique>(transitionMatrix, markovianStates, exitRates); } else { result = std::make_unique>(transitionMatrix); } storm::modelchecker::helper::setInformationFromOtherHelperNondeterministic(*result, *this, [&odd](storm::dd::Bdd const& s){ return s.toVector(odd); }); STORM_LOG_WARN_COND(!this->isProduceSchedulerSet(), "Scheduler extraction not supported in Hybrid engine."); return result; } template template > std::unique_ptr> HybridInfiniteHorizonHelper::createSparseHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector const& exitRates, storm::dd::Odd const& odd) const { std::unique_ptr> result; if (isContinuousTime()) { result = std::make_unique>(transitionMatrix, exitRates); } else { result = std::make_unique>(transitionMatrix); } storm::modelchecker::helper::setInformationFromOtherHelperDeterministic(*result, *this, [&odd](storm::dd::Bdd const& s){ return s.toVector(odd); }); return result; } template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; template class HybridInfiniteHorizonHelper; } } }