diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index f68db3db2..d3fa819b7 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -142,7 +142,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getMarkovianStates(), this->getModel().getExitRates()); + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRates()); storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector()); @@ -159,7 +159,7 @@ namespace storm { STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute long run average rewards in non-closed Markov automaton."); auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getMarkovianStates(), this->getModel().getExitRates()); + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getMarkovianStates(), this->getModel().getExitRates()); storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); diff --git a/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp b/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp index b884d6ee2..0487cb673 100644 --- a/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp +++ b/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.cpp @@ -5,6 +5,11 @@ namespace storm { namespace modelchecker { namespace helper { + template + SingleValueModelCheckerHelper::SingleValueModelCheckerHelper() : _produceScheduler(false) { + // Intentionally left empty + } + template void SingleValueModelCheckerHelper::setOptimizationDirection(storm::solver::OptimizationDirection const& direction) { _optimizationDirection = direction; @@ -67,6 +72,16 @@ namespace storm { STORM_LOG_ASSERT(isValueThresholdSet(), "Value Threshold comparison type was requested but not set before."); return _valueThreshold->second; } + + template + void SingleValueModelCheckerHelper::setProduceScheduler(bool value) { + _produceScheduler = value; + } + + template + bool SingleValueModelCheckerHelper::isProduceSchedulerSet() const { + return _produceScheduler; + } template class SingleValueModelCheckerHelper; template class SingleValueModelCheckerHelper; diff --git a/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h b/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h index 83ea27ae0..82184ad12 100644 --- a/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h +++ b/src/storm/modelchecker/helper/SingleValueModelCheckerHelper.h @@ -17,7 +17,8 @@ namespace storm { template class SingleValueModelCheckerHelper : public ModelCheckerHelper { public: - SingleValueModelCheckerHelper() = default; + + SingleValueModelCheckerHelper(); ~SingleValueModelCheckerHelper() = default; /*! @@ -91,9 +92,20 @@ namespace storm { */ ValueType const& getValueThresholdValue() const; + /*! + * 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; + private: boost::optional _optimizationDirection; boost::optional> _valueThreshold; + bool _produceScheduler; }; } } diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp index 6adbfc4d4..cc68d9fb7 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.cpp @@ -21,15 +21,27 @@ namespace storm { namespace helper { template - SparseNondeterministicInfiniteHorizonHelper::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions) : _transitionMatrix(transitionMatrix), _backwardTransitions(backwardTransitions), _markovianStates(nullptr), _exitRates(nullptr), _produceScheduler(false) { + SparseNondeterministicInfiniteHorizonHelper::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix) : _transitionMatrix(transitionMatrix), _backwardTransitions(nullptr), _mecDecomposition(nullptr), _markovianStates(nullptr), _exitRates(nullptr) { // Intentionally left empty. } template - SparseNondeterministicInfiniteHorizonHelper::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& markovianStates, std::vector const& exitRates) : _transitionMatrix(transitionMatrix), _backwardTransitions(backwardTransitions), _markovianStates(&markovianStates), _exitRates(&exitRates), _produceScheduler(false) { + SparseNondeterministicInfiniteHorizonHelper::SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector const& exitRates) : _transitionMatrix(transitionMatrix), _backwardTransitions(nullptr), _mecDecomposition(nullptr), _markovianStates(&markovianStates), _exitRates(&exitRates) { // Intentionally left empty. } + template + void SparseNondeterministicInfiniteHorizonHelper::provideBackwardTransitions(storm::storage::SparseMatrix const& backwardTransitions) { + STORM_LOG_WARN_COND(_backwardTransitions == nullptr, "Backwards transitions were provided but they were already computed or set before."); + _backwardTransitions = &backwardTransitions; + } + + template + void SparseNondeterministicInfiniteHorizonHelper::provideMaximalEndComponentDecomposition(storm::storage::MaximalEndComponentDecomposition const& mecDecomposition) { + STORM_LOG_WARN_COND(_mecDecomposition == nullptr, "Backwards transitions were provided but they were already computed or set before."); + _mecDecomposition = &mecDecomposition; + } + template std::vector SparseNondeterministicInfiniteHorizonHelper::computeLongRunAverageProbabilities(Environment const& env, storm::storage::BitVector const& psiStates) { return computeLongRunAverageValues(env, @@ -96,7 +108,7 @@ namespace storm { } // If requested, allocate memory for the choices made - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { if (!_producedOptimalChoices.is_initialized()) { _producedOptimalChoices.emplace(); } @@ -104,40 +116,37 @@ namespace storm { } // Start by decomposing the Model into its MECs. - storm::storage::MaximalEndComponentDecomposition mecDecomposition(_transitionMatrix, _backwardTransitions); + if (_mecDecomposition == nullptr) { + // The decomposition has not been provided or computed, yet. + if (_backwardTransitions == nullptr) { + _computedBackwardTransitions = _transitionMatrix.transpose(true); + _backwardTransitions = &_computedBackwardTransitions; + } + _computedMecDecomposition = storm::storage::MaximalEndComponentDecomposition(_transitionMatrix, *_backwardTransitions); + _mecDecomposition = &_computedMecDecomposition; + } // Compute the long-run average for all end components in isolation. std::vector mecLraValues; - mecLraValues.reserve(mecDecomposition.size()); - for (auto const& mec : mecDecomposition) { + mecLraValues.reserve(_mecDecomposition->size()); + for (auto const& mec : *_mecDecomposition) { mecLraValues.push_back(computeLraForMec(underlyingSolverEnvironment, stateRewardsGetter, actionRewardsGetter, mec)); } // Solve the resulting SSP where end components are collapsed into single auxiliary states - return buildAndSolveSsp(underlyingSolverEnvironment, mecDecomposition, mecLraValues); - } - - - template - void SparseNondeterministicInfiniteHorizonHelper::setProduceScheduler(bool value) { - _produceScheduler = value; - } - - template - bool SparseNondeterministicInfiniteHorizonHelper::isProduceSchedulerSet() const { - return _produceScheduler; + return buildAndSolveSsp(underlyingSolverEnvironment, mecLraValues); } template std::vector const& SparseNondeterministicInfiniteHorizonHelper::getProducedOptimalChoices() const { - STORM_LOG_ASSERT(isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); + STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); return _producedOptimalChoices.get(); } template std::vector& SparseNondeterministicInfiniteHorizonHelper::getProducedOptimalChoices() { - STORM_LOG_ASSERT(isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); + STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested."); STORM_LOG_ASSERT(_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?"); return _producedOptimalChoices.get(); } @@ -169,7 +178,7 @@ namespace storm { // Singleton MECs have to consist of a Markovian state because of the non-Zenoness assumption. Then, there is just one possible choice. STORM_LOG_THROW(_markovianStates->get(state), storm::exceptions::InvalidOperationException, "Markov Automaton has Zeno behavior. Computation of Long Run Average values not supported."); STORM_LOG_ASSERT(mec.begin()->second.size() == 1, "Markovian state has Nondeterministic behavior."); - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { _producedOptimalChoices.get()[state] = 0; } return stateRewardsGetter(state) + (*_exitRates)[state] * actionRewardsGetter(*choiceIt); @@ -184,7 +193,7 @@ namespace storm { bestChoice = *choiceIt; } } - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { _producedOptimalChoices.get()[state] = bestChoice - _transitionMatrix.getRowGroupIndices()[state]; } return bestValue + stateRewardsGetter(state); @@ -200,7 +209,7 @@ namespace storm { STORM_LOG_INFO("Selecting 'VI' as the solution technique for long-run properties to guarantee sound results. If you want to override this, please explicitly specify a different LRA method."); method = storm::solver::LraMethod::ValueIteration; } - STORM_LOG_ERROR_COND(!isProduceSchedulerSet() || method == storm::solver::LraMethod::ValueIteration, "Scheduler generation not supported for the chosen LRA method. Try value-iteration."); + STORM_LOG_ERROR_COND(!this->isProduceSchedulerSet() || method == storm::solver::LraMethod::ValueIteration, "Scheduler generation not supported for the chosen LRA method. Try value-iteration."); if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMecLp(env, stateRewardsGetter, actionRewardsGetter, mec); } else if (method == storm::solver::LraMethod::ValueIteration) { @@ -216,7 +225,7 @@ namespace storm { // Collect some parameters of the computation ValueType aperiodicFactor = storm::utility::convertNumber(env.solver().lra().getAperiodicFactor()); std::vector* optimalChoices = nullptr; - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { optimalChoices = &_producedOptimalChoices.get(); } @@ -296,7 +305,7 @@ namespace storm { } solver->optimize(); - STORM_LOG_THROW(!isProduceSchedulerSet(), storm::exceptions::NotImplementedException, "Scheduler extraction is not yet implemented for LP based LRA method."); + STORM_LOG_THROW(!this->isProduceSchedulerSet(), storm::exceptions::NotImplementedException, "Scheduler extraction is not yet implemented for LP based LRA method."); return solver->getContinuousValue(k); } @@ -339,7 +348,8 @@ namespace storm { } template - std::vector SparseNondeterministicInfiniteHorizonHelper::buildAndSolveSsp(Environment const& env, storm::storage::MaximalEndComponentDecomposition const& mecDecomposition, std::vector const& mecLraValues) { + std::vector SparseNondeterministicInfiniteHorizonHelper::buildAndSolveSsp(Environment const& env, std::vector const& mecLraValues) { + STORM_LOG_ASSERT(_mecDecomposition != nullptr, "Decomposition not computed, yet."); // Let's improve readability a bit uint64_t numberOfStates = _transitionMatrix.getRowGroupCount(); @@ -353,8 +363,8 @@ namespace storm { // and create a mapping from states that lie in a MEC to the corresponding MEC index. storm::storage::BitVector statesInMecs(numberOfStates); std::vector inputToSspStateMap(numberOfStates, std::numeric_limits::max()); - for (uint64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) { - for (auto const& stateChoicesPair : mecDecomposition[currentMecIndex]) { + for (uint64_t currentMecIndex = 0; currentMecIndex < _mecDecomposition->size(); ++currentMecIndex) { + for (auto const& stateChoicesPair : (*_mecDecomposition)[currentMecIndex]) { statesInMecs.set(stateChoicesPair.first); inputToSspStateMap[stateChoicesPair.first] = currentMecIndex; } @@ -379,7 +389,7 @@ namespace storm { // The next step is to create the SSP matrix and the right-hand side of the SSP. std::vector rhs; - uint64_t numberOfSspStates = numberOfStatesNotInMecs + mecDecomposition.size(); + uint64_t numberOfSspStates = numberOfStatesNotInMecs + _mecDecomposition->size(); typename storm::storage::SparseMatrixBuilder sspMatrixBuilder(0, numberOfSspStates , 0, false, true, numberOfSspStates); // If the source state of a transition is not contained in any MEC, we copy its choices (and perform the necessary modifications). uint64_t currentSspChoice = 0; @@ -392,8 +402,8 @@ namespace storm { } } // Now we construct the choices for the auxiliary states which reflect former MEC states. - for (uint64_t mecIndex = 0; mecIndex < mecDecomposition.size(); ++mecIndex) { - storm::storage::MaximalEndComponent const& mec = mecDecomposition[mecIndex]; + for (uint64_t mecIndex = 0; mecIndex < _mecDecomposition->size(); ++mecIndex) { + storm::storage::MaximalEndComponent const& mec = (*_mecDecomposition)[mecIndex]; sspMatrixBuilder.newRowGroup(currentSspChoice); for (auto const& stateChoicesPair : mec) { uint64_t const& mecState = stateChoicesPair.first; @@ -403,7 +413,7 @@ namespace storm { if (choicesInMec.find(choice) == choicesInMec.end()) { rhs.push_back(storm::utility::zero()); addSspMatrixChoice(choice, _transitionMatrix, inputToSspStateMap, numberOfStatesNotInMecs, currentSspChoice, sspMatrixBuilder); - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { // Later we need to be able to map this choice back to the original input model sspMecExitChoicesToOriginalMap.emplace_back(mecState, choice - nondeterministicChoiceIndices[mecState]); } @@ -413,7 +423,7 @@ namespace storm { } // For each auxiliary state, there is the option to achieve the reward value of the LRA associated with the MEC. rhs.push_back(mecLraValues[mecIndex]); - if (isProduceSchedulerSet()) { + if (this->isProduceSchedulerSet()) { // Insert some invalid values so we can later detect that this choice is not an exit choice sspMecExitChoicesToOriginalMap.emplace_back(std::numeric_limits::max(), std::numeric_limits::max()); } @@ -429,7 +439,7 @@ namespace storm { std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, sspMatrix); solver->setHasUniqueSolution(); solver->setHasNoEndComponents(); - solver->setTrackScheduler(isProduceSchedulerSet()); + solver->setTrackScheduler(this->isProduceSchedulerSet()); auto lowerUpperBounds = std::minmax_element(mecLraValues.begin(), mecLraValues.end()); solver->setLowerBound(*lowerUpperBounds.first); solver->setUpperBound(*lowerUpperBounds.second); @@ -440,7 +450,7 @@ namespace storm { solver->solveEquations(env, this->getOptimizationDirection(), x, rhs); // Prepare scheduler (if requested) - if (isProduceSchedulerSet() && solver->hasScheduler()) { + if (this->isProduceSchedulerSet() && solver->hasScheduler()) { // Translate result for ssp matrix to original model auto const& sspChoices = solver->getSchedulerChoices(); // We first take care of non-mec states @@ -451,7 +461,7 @@ namespace storm { // a) we take an exit (non-MEC) choice at the given state // b) we have to take a MEC choice at the given state in a way that eventually an exit state of the MEC is reached uint64_t exitChoiceOffset = sspMatrix.getRowGroupIndices()[numberOfStatesNotInMecs]; - for (auto const& mec : mecDecomposition) { + for (auto const& mec : *_mecDecomposition) { // Get the sspState of this MEC (using one representative mec state) auto const& sspState = inputToSspStateMap[mec.begin()->first]; uint64_t sspChoiceIndex = sspMatrix.getRowGroupIndices()[sspState] + sspChoices[sspState]; @@ -474,12 +484,17 @@ namespace storm { _producedOptimalChoices.get()[stateActions.first] = std::numeric_limits::max(); } } + // Ensure that backwards transitions are available + if (_backwardTransitions == nullptr) { + _computedBackwardTransitions = _transitionMatrix.transpose(true); + _backwardTransitions = &_computedBackwardTransitions; + } // Now start a backwards DFS std::vector stack = {originalStateChoice.first}; while (!stack.empty()) { uint64_t currentState = stack.back(); stack.pop_back(); - for (auto const& backwardsTransition : _backwardTransitions.getRowGroup(currentState)) { + for (auto const& backwardsTransition : _backwardTransitions->getRowGroup(currentState)) { uint64_t predecessorState = backwardsTransition.getColumn(); if (mec.containsState(predecessorState)) { auto& selectedPredChoice = _producedOptimalChoices.get()[predecessorState]; @@ -506,7 +521,7 @@ namespace storm { } } } else { - STORM_LOG_ERROR_COND(!isProduceSchedulerSet(), "Requested to produce a scheduler, but no scheduler was generated."); + STORM_LOG_ERROR_COND(!this->isProduceSchedulerSet(), "Requested to produce a scheduler, but no scheduler was generated."); } // Prepare result vector. diff --git a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h index a58d91025..3a63e7946 100644 --- a/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h +++ b/src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicInfiniteHorizonHelper.h @@ -21,12 +21,26 @@ namespace storm { /*! * Initializes the helper for a discrete time (i.e. MDP) */ - SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions); + SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix); /*! * Initializes the helper for a continuous time (i.e. MA) */ - SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& markovianStates, std::vector const& exitRates); + SparseNondeterministicInfiniteHorizonHelper(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, std::vector const& exitRates); + + /*! + * Provides backward transitions that can be used during the computation. + * Providing them is optional. If they are not provided, they will be computed internally + * Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the backwardstransitions remains valid. + */ + void provideBackwardTransitions(storm::storage::SparseMatrix const& backwardsTransitions); + + /*! + * Provides the maximal end component decomposition that can be used during the computation. + * Providing the decomposition is optional. If they are not provided, they will be computed internally + * Be aware that this class does not take ownership, i.e. the caller has to make sure that the reference to the decomposition remains valid. + */ + void provideMaximalEndComponentDecomposition(storm::storage::MaximalEndComponentDecomposition const& decomposition); /*! * Computes the long run average probabilities, i.e., the fraction of the time we are in a psiState @@ -52,16 +66,6 @@ namespace storm { */ std::vector computeLongRunAverageValues(Environment const& env, std::function const& stateValuesGetter, std::function const& actionValuesGetter); - /*! - * 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; - /*! * @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. @@ -107,14 +111,16 @@ namespace storm { /*! * @return Lra values for each state */ - std::vector buildAndSolveSsp(Environment const& env, storm::storage::MaximalEndComponentDecomposition const& mecDecomposition, std::vector const& mecLraValues); + std::vector buildAndSolveSsp(Environment const& env, std::vector const& mecLraValues); private: storm::storage::SparseMatrix const& _transitionMatrix; - storm::storage::SparseMatrix const& _backwardTransitions; + storm::storage::SparseMatrix const* _backwardTransitions; + storm::storage::SparseMatrix _computedBackwardTransitions; + storm::storage::MaximalEndComponentDecomposition const* _mecDecomposition; + storm::storage::MaximalEndComponentDecomposition _computedMecDecomposition; storm::storage::BitVector const* _markovianStates; std::vector const* _exitRates; - bool _produceScheduler; boost::optional> _producedOptimalChoices; }; diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index bc0321317..3b9062ea3 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -227,7 +227,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions()); + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); auto values = helper.computeLongRunAverageProbabilities(env, subResult.getTruthValuesVector()); @@ -242,7 +242,7 @@ namespace storm { std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask); - storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions()); + storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper helper(this->getModel().getTransitionMatrix()); storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel()); auto values = helper.computeLongRunAverageRewards(env, rewardModel.get()); std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(values)));