#include "storm/transformer/SparseParametricModelSimplifier.h" #include "storm/adapters/CarlAdapter.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/solver/stateelimination/NondeterministicModelStateEliminator.h" #include "storm/storage/FlexibleSparseMatrix.h" #include "storm/utility/vector.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/InvalidPropertyException.h" namespace storm { namespace transformer { template SparseParametricModelSimplifier::SparseParametricModelSimplifier(SparseModelType const& model) : originalModel(model) { // intentionally left empty } template bool SparseParametricModelSimplifier::simplify(storm::logic::Formula const& formula) { // Make sure that there is no old result from a previous call simplifiedModel = nullptr; simplifiedFormula = nullptr; if (formula.isProbabilityOperatorFormula()) { storm::logic::ProbabilityOperatorFormula const& probOpForm = formula.asProbabilityOperatorFormula(); if (probOpForm.getSubformula().isUntilFormula()) { return simplifyForUntilProbabilities(probOpForm); } else if (probOpForm.getSubformula().isReachabilityProbabilityFormula()) { return simplifyForReachabilityProbabilities(probOpForm); } else if (probOpForm.getSubformula().isBoundedUntilFormula()) { return simplifyForBoundedUntilProbabilities(probOpForm); } } else if (formula.isRewardOperatorFormula()) { storm::logic::RewardOperatorFormula rewOpForm = formula.asRewardOperatorFormula(); STORM_LOG_THROW((rewOpForm.hasRewardModelName() && originalModel.hasRewardModel(rewOpForm.getRewardModelName())) || (!rewOpForm.hasRewardModelName() && originalModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model specified by formula " << formula << " is not available in the given model."); if (rewOpForm.getSubformula().isReachabilityRewardFormula()) { return simplifyForReachabilityRewards(rewOpForm); } else if (rewOpForm.getSubformula().isCumulativeRewardFormula()) { return simplifyForCumulativeRewards(rewOpForm); } } // reaching this point means that the provided formula is not supported. Thus, no simplification is possible. STORM_LOG_DEBUG("Simplification not possible because the formula is not suppoerted. Formula: " << formula); return false; } template std::shared_ptr SparseParametricModelSimplifier::getSimplifiedModel() const { STORM_LOG_THROW(simplifiedModel, storm::exceptions::InvalidStateException, "Tried to get the simplified model but simplification was not invoked before."); return simplifiedModel; } template std::shared_ptr SparseParametricModelSimplifier::getSimplifiedFormula() const { STORM_LOG_THROW(simplifiedFormula, storm::exceptions::InvalidStateException, "Tried to get the simplified formula but simplification was not invoked before."); return simplifiedFormula; } template bool SparseParametricModelSimplifier::simplifyForUntilProbabilities(storm::logic::ProbabilityOperatorFormula const& formula) { // If this method was not overriden by any subclass, simplification is not possible STORM_LOG_DEBUG("Simplification not possible because the formula is not suppoerted. Formula: " << formula); return false; } template bool SparseParametricModelSimplifier::simplifyForReachabilityProbabilities(storm::logic::ProbabilityOperatorFormula const& formula) { // transform to until formula auto untilFormula = std::make_shared(storm::logic::Formula::getTrueFormula(), formula.getSubformula().asEventuallyFormula().getSubformula().asSharedPointer()); return simplifyForUntilProbabilities(storm::logic::ProbabilityOperatorFormula(untilFormula, formula.getOperatorInformation())); } template bool SparseParametricModelSimplifier::simplifyForBoundedUntilProbabilities(storm::logic::ProbabilityOperatorFormula const& formula) { // If this method was not overriden by any subclass, simplification is not possible STORM_LOG_DEBUG("Simplification not possible because the formula is not suppoerted. Formula: " << formula); return false; } template bool SparseParametricModelSimplifier::simplifyForReachabilityRewards(storm::logic::RewardOperatorFormula const& formula) { // If this method was not overriden by any subclass, simplification is not possible STORM_LOG_DEBUG("Simplification not possible because the formula is not suppoerted. Formula: " << formula); return false; } template bool SparseParametricModelSimplifier::simplifyForCumulativeRewards(storm::logic::RewardOperatorFormula const& formula) { // If this method was not overriden by any subclass, simplification is not possible STORM_LOG_DEBUG("Simplification not possible because the formula is not suppoerted. Formula: " << formula); return false; } template std::shared_ptr SparseParametricModelSimplifier::eliminateConstantDeterministicStates(SparseModelType const& model, boost::optional const& rewardModelName) { storm::storage::SparseMatrix const& sparseMatrix = model.getTransitionMatrix(); // Get the states without any label storm::storage::BitVector considerForElimination(model.getNumberOfStates(), false); for(auto const& label : model.getStateLabeling().getLabels()) { considerForElimination |= model.getStateLabeling().getStates(label); } considerForElimination.complement(); // get the action-based reward values std::vector actionRewards; if(rewardModelName) { actionRewards = model.getRewardModel(*rewardModelName).getTotalRewardVector(sparseMatrix); } else { actionRewards = std::vector(model.getTransitionMatrix().getRowCount(), storm::utility::zero()); } // Find the states that are to be eliminated storm::storage::BitVector selectedStates = considerForElimination; for (auto state : considerForElimination) { if (sparseMatrix.getRowGroupSize(state) == 1 && (!rewardModelName.is_initialized() || storm::utility::isConstant(actionRewards[sparseMatrix.getRowGroupIndices()[state]]))) { for (auto const& entry : sparseMatrix.getRowGroup(state)) { if(!storm::utility::isConstant(entry.getValue())) { selectedStates.set(state, false); break; } } } else { selectedStates.set(state, false); } } // invoke elimination and obtain resulting transition matrix storm::storage::FlexibleSparseMatrix flexibleMatrix(sparseMatrix); storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(sparseMatrix.transpose(), true); storm::solver::stateelimination::NondeterministicModelStateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions, actionRewards); for(auto state : selectedStates) { stateEliminator.eliminateState(state, true); } selectedStates.complement(); auto keptRows = sparseMatrix.getRowFilter(selectedStates); storm::storage::SparseMatrix newTransitionMatrix = flexibleMatrix.createSparseMatrix(keptRows, selectedStates); // obtain the reward model for the resulting system std::unordered_map rewardModels; if(rewardModelName) { storm::utility::vector::filterVectorInPlace(actionRewards, keptRows); rewardModels.insert(std::make_pair(*rewardModelName, typename SparseModelType::RewardModelType(boost::none, std::move(actionRewards)))); } return std::make_shared(std::move(newTransitionMatrix), model.getStateLabeling().getSubLabeling(selectedStates), std::move(rewardModels)); } template class SparseParametricModelSimplifier>; template class SparseParametricModelSimplifier>; } }