11 changed files with 1063 additions and 958 deletions
			
			
		- 
					611src/storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessor.cpp
 - 
					105src/storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessor.h
 - 
					105src/storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessorResult.h
 - 
					137src/storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessorTask.h
 - 
					103src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.cpp
 - 
					33src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h
 - 
					424src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessor.cpp
 - 
					105src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessor.h
 - 
					95src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessorResult.h
 - 
					230src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveRewardAnalysis.cpp
 - 
					73src/storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveRewardAnalysis.h
 
@ -1,611 +0,0 @@ | 
				
			|||
#include "storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessor.h"
 | 
				
			|||
 | 
				
			|||
#include <algorithm>
 | 
				
			|||
#include <set>
 | 
				
			|||
 | 
				
			|||
#include "storm/models/sparse/Mdp.h"
 | 
				
			|||
#include "storm/models/sparse/MarkovAutomaton.h"
 | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h"
 | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | 
				
			|||
#include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h"
 | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | 
				
			|||
#include "storm/storage/MaximalEndComponentDecomposition.h"
 | 
				
			|||
#include "storm/storage/memorystructure/MemoryStructureBuilder.h"
 | 
				
			|||
#include "storm/storage/memorystructure/SparseModelMemoryProduct.h"
 | 
				
			|||
#include "storm/storage/expressions/ExpressionManager.h"
 | 
				
			|||
#include "storm/transformer/EndComponentEliminator.h"
 | 
				
			|||
#include "storm/utility/macros.h"
 | 
				
			|||
#include "storm/utility/vector.h"
 | 
				
			|||
#include "storm/utility/graph.h"
 | 
				
			|||
#include "storm/settings/SettingsManager.h"
 | 
				
			|||
#include "storm/settings/modules/GeneralSettings.h"
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/InvalidPropertyException.h"
 | 
				
			|||
#include "storm/exceptions/UnexpectedException.h"
 | 
				
			|||
#include "storm/exceptions/NotImplementedException.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
                 | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::preprocess(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula) { | 
				
			|||
                 | 
				
			|||
                PreprocessorData data(originalModel); | 
				
			|||
                 | 
				
			|||
                //Invoke preprocessing on the individual objectives
 | 
				
			|||
                for (auto const& subFormula : originalFormula.getSubformulas()) { | 
				
			|||
                    STORM_LOG_INFO("Preprocessing objective " << *subFormula<< "."); | 
				
			|||
                    data.objectives.push_back(std::make_shared<Objective<ValueType>>()); | 
				
			|||
                    data.objectives.back()->originalFormula = subFormula; | 
				
			|||
                    data.finiteRewardCheckObjectives.resize(data.objectives.size(), false); | 
				
			|||
                    data.upperResultBoundObjectives.resize(data.objectives.size(), false); | 
				
			|||
                    if (data.objectives.back()->originalFormula->isOperatorFormula()) { | 
				
			|||
                        preprocessOperatorFormula(data.objectives.back()->originalFormula->asOperatorFormula(), data); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Could not preprocess the subformula " << *subFormula << " of " << originalFormula << " because it is not supported"); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Incorporate the required memory into the state space
 | 
				
			|||
                storm::storage::SparseModelMemoryProduct<ValueType> product = data.memory->product(originalModel); | 
				
			|||
                std::shared_ptr<SparseModelType> preprocessedModel = std::dynamic_pointer_cast<SparseModelType>(product.build()); | 
				
			|||
                 | 
				
			|||
                auto backwardTransitions = preprocessedModel->getBackwardTransitions(); | 
				
			|||
                 | 
				
			|||
                // compute the end components of the model (if required)
 | 
				
			|||
                bool endComponentAnalysisRequired = false; | 
				
			|||
                for (auto& task : data.tasks) { | 
				
			|||
                    endComponentAnalysisRequired = endComponentAnalysisRequired || task->requiresEndComponentAnalysis(); | 
				
			|||
                } | 
				
			|||
                if (endComponentAnalysisRequired) { | 
				
			|||
                    // TODO
 | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "End component analysis required but currently not implemented."); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                for (auto& task : data.tasks) { | 
				
			|||
                    task->perform(*preprocessedModel); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Remove reward models that are not needed anymore
 | 
				
			|||
                std::set<std::string> relevantRewardModels; | 
				
			|||
                for (auto const& obj : data.objectives) { | 
				
			|||
                    obj->formula->gatherReferencedRewardModels(relevantRewardModels); | 
				
			|||
                } | 
				
			|||
                preprocessedModel->restrictRewardModels(relevantRewardModels); | 
				
			|||
                 | 
				
			|||
                // Build the actual result
 | 
				
			|||
                return buildResult(originalModel, originalFormula, data, preprocessedModel, backwardTransitions); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename SparseModelType> | 
				
			|||
            SparseMultiObjectivePreprocessor<SparseModelType>::PreprocessorData::PreprocessorData(SparseModelType const& model) : originalModel(model) { | 
				
			|||
                memory = std::make_shared<storm::storage::MemoryStructure>(storm::storage::MemoryStructureBuilder<ValueType, RewardModelType>::buildTrivialMemoryStructure(model)); | 
				
			|||
                 | 
				
			|||
                // The memoryLabelPrefix should not be a prefix of a state label of the given model to ensure uniqueness of label names
 | 
				
			|||
                memoryLabelPrefix = "mem"; | 
				
			|||
                while (true) { | 
				
			|||
                    bool prefixIsUnique = true; | 
				
			|||
                    for (auto const& label : originalModel.getStateLabeling().getLabels()) { | 
				
			|||
                        if (memoryLabelPrefix.size() <= label.size()) { | 
				
			|||
                            if (std::mismatch(memoryLabelPrefix.begin(), memoryLabelPrefix.end(), label.begin()).first == memoryLabelPrefix.end()) { | 
				
			|||
                                prefixIsUnique = false; | 
				
			|||
                                memoryLabelPrefix = "_" + memoryLabelPrefix; | 
				
			|||
                                break; | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (prefixIsUnique) { | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // The rewardModelNamePrefix should not be a prefix of a reward model name of the given model to ensure uniqueness of reward model names
 | 
				
			|||
                rewardModelNamePrefix = "obj"; | 
				
			|||
                while (true) { | 
				
			|||
                    bool prefixIsUnique = true; | 
				
			|||
                    for (auto const& label : originalModel.getStateLabeling().getLabels()) { | 
				
			|||
                        if (memoryLabelPrefix.size() <= label.size()) { | 
				
			|||
                            if (std::mismatch(memoryLabelPrefix.begin(), memoryLabelPrefix.end(), label.begin()).first == memoryLabelPrefix.end()) { | 
				
			|||
                                prefixIsUnique = false; | 
				
			|||
                                memoryLabelPrefix = "_" + memoryLabelPrefix; | 
				
			|||
                                break; | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (prefixIsUnique) { | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessOperatorFormula(storm::logic::OperatorFormula const& formula, PreprocessorData& data) { | 
				
			|||
                 | 
				
			|||
                Objective<ValueType>& objective = *data.objectives.back(); | 
				
			|||
                 | 
				
			|||
                // Check whether the complementary event is considered
 | 
				
			|||
                objective.considersComplementaryEvent = formula.isProbabilityOperatorFormula() && formula.getSubformula().isGloballyFormula(); | 
				
			|||
                 | 
				
			|||
                storm::logic::OperatorInformation opInfo; | 
				
			|||
                if (formula.hasBound()) { | 
				
			|||
                    opInfo.bound = formula.getBound(); | 
				
			|||
                    // Invert the bound (if necessary)
 | 
				
			|||
                    if (objective.considersComplementaryEvent) { | 
				
			|||
                        opInfo.bound->threshold = opInfo.bound->threshold.getManager().rational(storm::utility::one<storm::RationalNumber>()) - opInfo.bound->threshold; | 
				
			|||
                        switch (opInfo.bound->comparisonType) { | 
				
			|||
                            case storm::logic::ComparisonType::Greater: | 
				
			|||
                                opInfo.bound->comparisonType = storm::logic::ComparisonType::Less; | 
				
			|||
                                break; | 
				
			|||
                            case storm::logic::ComparisonType::GreaterEqual: | 
				
			|||
                                opInfo.bound->comparisonType = storm::logic::ComparisonType::LessEqual; | 
				
			|||
                                break; | 
				
			|||
                            case storm::logic::ComparisonType::Less: | 
				
			|||
                                opInfo.bound->comparisonType = storm::logic::ComparisonType::Greater; | 
				
			|||
                                break; | 
				
			|||
                            case storm::logic::ComparisonType::LessEqual: | 
				
			|||
                                opInfo.bound->comparisonType = storm::logic::ComparisonType::GreaterEqual; | 
				
			|||
                                break; | 
				
			|||
                            default: | 
				
			|||
                                STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Current objective " << formula << " has unexpected comparison type"); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (storm::logic::isLowerBound(opInfo.bound->comparisonType)) { | 
				
			|||
                        opInfo.optimalityType = storm::solver::OptimizationDirection::Maximize; | 
				
			|||
                    } else { | 
				
			|||
                        opInfo.optimalityType = storm::solver::OptimizationDirection::Minimize; | 
				
			|||
                    } | 
				
			|||
                    STORM_LOG_WARN_COND(!formula.hasOptimalityType(), "Optimization direction of formula " << formula << " ignored as the formula also specifies a threshold."); | 
				
			|||
                } else if (formula.hasOptimalityType()){ | 
				
			|||
                    opInfo.optimalityType = formula.getOptimalityType(); | 
				
			|||
                    // Invert the optimality type (if necessary)
 | 
				
			|||
                    if (objective.considersComplementaryEvent) { | 
				
			|||
                        opInfo.optimalityType = storm::solver::invert(opInfo.optimalityType.get()); | 
				
			|||
                    } | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Objective " << formula << " does not specify whether to minimize or maximize"); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                if (formula.isProbabilityOperatorFormula()){ | 
				
			|||
                    preprocessProbabilityOperatorFormula(formula.asProbabilityOperatorFormula(), opInfo, data); | 
				
			|||
                } else if (formula.isRewardOperatorFormula()){ | 
				
			|||
                    preprocessRewardOperatorFormula(formula.asRewardOperatorFormula(), opInfo, data); | 
				
			|||
                } else if (formula.isTimeOperatorFormula()){ | 
				
			|||
                    preprocessTimeOperatorFormula(formula.asTimeOperatorFormula(), opInfo, data); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Could not preprocess the objective " << formula << " because it is not supported"); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                 | 
				
			|||
                // Probabilities are between zero and one
 | 
				
			|||
                data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                data.objectives.back()->upperResultBound = storm::utility::one<ValueType>(); | 
				
			|||
                 | 
				
			|||
                if (formula.getSubformula().isUntilFormula()){ | 
				
			|||
                    preprocessUntilFormula(formula.getSubformula().asUntilFormula(), opInfo, data); | 
				
			|||
                } else if (formula.getSubformula().isBoundedUntilFormula()){ | 
				
			|||
                    preprocessBoundedUntilFormula(formula.getSubformula().asBoundedUntilFormula(), opInfo, data); | 
				
			|||
                } else if (formula.getSubformula().isGloballyFormula()){ | 
				
			|||
                    preprocessGloballyFormula(formula.getSubformula().asGloballyFormula(), opInfo, data); | 
				
			|||
                } else if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                    preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                 | 
				
			|||
                STORM_LOG_THROW((formula.hasRewardModelName() && data.originalModel.hasRewardModel(formula.getRewardModelName())) | 
				
			|||
                                || (!formula.hasRewardModelName() && data.originalModel.hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model is not unique or the formula " << formula << " does not specify an existing reward model."); | 
				
			|||
                 | 
				
			|||
                std::string rewardModelName; | 
				
			|||
                if (formula.hasRewardModelName()) { | 
				
			|||
                    rewardModelName = formula.getRewardModelName(); | 
				
			|||
                    STORM_LOG_THROW(data.originalModel.hasRewardModel(rewardModelName), storm::exceptions::InvalidPropertyException, "The reward model specified by formula " << formula << " does not exist in the model"); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(data.originalModel.hasUniqueRewardModel(), storm::exceptions::InvalidOperationException, "The formula " << formula << " does not specify a reward model name and the reward model is not unique."); | 
				
			|||
                    rewardModelName = data.originalModel.getRewardModels().begin()->first; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                 | 
				
			|||
                if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                    preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data, rewardModelName); | 
				
			|||
                } else if (formula.getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                    preprocessCumulativeRewardFormula(formula.getSubformula().asCumulativeRewardFormula(), opInfo, data, rewardModelName); | 
				
			|||
                } else if (formula.getSubformula().isTotalRewardFormula()) { | 
				
			|||
                    preprocessTotalRewardFormula(opInfo, data, rewardModelName); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                // Time formulas are only supported for Markov automata
 | 
				
			|||
                STORM_LOG_THROW(data.originalModel.isOfType(storm::models::ModelType::MarkovAutomaton), storm::exceptions::InvalidPropertyException, "Time operator formulas are only supported for Markov automata."); | 
				
			|||
                 | 
				
			|||
                data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                 | 
				
			|||
                if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                    preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessUntilFormula(storm::logic::UntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, std::shared_ptr<storm::logic::Formula const> subformula) { | 
				
			|||
                 | 
				
			|||
                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(data.originalModel); | 
				
			|||
                storm::storage::BitVector rightSubformulaResult = mc.check(formula.getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                storm::storage::BitVector leftSubformulaResult = mc.check(formula.getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                // Check if the formula is already satisfied in the initial state because then the transformation to expected rewards will fail.
 | 
				
			|||
                // TODO: Handle this case more properly
 | 
				
			|||
                STORM_LOG_THROW((data.originalModel.getInitialStates() & rightSubformulaResult).empty(), storm::exceptions::NotImplementedException, "The Probability for the objective " << *data.objectives.back()->originalFormula << " is always one as the rhs of the until formula is true in the initial state. This (trivial) case is currently not implemented."); | 
				
			|||
                 | 
				
			|||
                // Create a memory structure that stores whether a non-PhiState or a PsiState has already been reached
 | 
				
			|||
                storm::storage::MemoryStructureBuilder<ValueType, RewardModelType> builder(2, data.originalModel); | 
				
			|||
                std::string relevantStatesLabel = data.memoryLabelPrefix + "_obj" + std::to_string(data.objectives.size()) + "_relevant"; | 
				
			|||
                builder.setLabel(0, relevantStatesLabel); | 
				
			|||
                storm::storage::BitVector nonRelevantStates = ~leftSubformulaResult | rightSubformulaResult; | 
				
			|||
                builder.setTransition(0, 0, ~nonRelevantStates); | 
				
			|||
                builder.setTransition(0, 1, nonRelevantStates); | 
				
			|||
                builder.setTransition(1, 1, storm::storage::BitVector(data.originalModel.getNumberOfStates(), true)); | 
				
			|||
                for (auto const& initState : data.originalModel.getInitialStates()) { | 
				
			|||
                    builder.setInitialMemoryState(initState, nonRelevantStates.get(initState) ? 1 : 0); | 
				
			|||
                } | 
				
			|||
                storm::storage::MemoryStructure objectiveMemory = builder.build(); | 
				
			|||
                data.memory = std::make_shared<storm::storage::MemoryStructure>(data.memory->product(objectiveMemory)); | 
				
			|||
                 | 
				
			|||
                std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size()); | 
				
			|||
                if (subformula == nullptr) { | 
				
			|||
                    subformula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                } | 
				
			|||
                data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(subformula, rewardModelName, opInfo); | 
				
			|||
                 | 
				
			|||
                auto relevantStatesFormula = std::make_shared<storm::logic::AtomicLabelFormula>(relevantStatesLabel); | 
				
			|||
                data.tasks.push_back(std::make_shared<SparseMultiObjectivePreprocessorReachProbToTotalRewTask<SparseModelType>>(data.objectives.back(), relevantStatesFormula, formula.getRightSubformula().asSharedPointer())); | 
				
			|||
                 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                 | 
				
			|||
                // Check how to handle this query
 | 
				
			|||
                if (formula.isMultiDimensional() || formula.getTimeBoundReference().isRewardBound()) { | 
				
			|||
                    data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo); | 
				
			|||
                } else if (!formula.hasLowerBound() || (!formula.isLowerBoundStrict() && storm::utility::isZero(formula.template getLowerBound<storm::RationalNumber>()))) { | 
				
			|||
                    std::shared_ptr<storm::logic::Formula const> subformula; | 
				
			|||
                    if (!formula.hasUpperBound()) { | 
				
			|||
                        // The formula is actually unbounded
 | 
				
			|||
                        subformula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(!data.originalModel.isOfType(storm::models::ModelType::MarkovAutomaton) || formula.getTimeBoundReference().isTimeBound(), storm::exceptions::InvalidPropertyException, "Bounded until formulas for Markov Automata are only allowed when time bounds are considered."); | 
				
			|||
                        storm::logic::TimeBound bound(formula.isUpperBoundStrict(), formula.getUpperBound()); | 
				
			|||
                        subformula = std::make_shared<storm::logic::CumulativeRewardFormula>(bound, formula.getTimeBoundReference()); | 
				
			|||
                    } | 
				
			|||
                    preprocessUntilFormula(storm::logic::UntilFormula(formula.getLeftSubformula().asSharedPointer(), formula.getRightSubformula().asSharedPointer()), opInfo, data, subformula); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Property " << formula << "is not supported"); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessGloballyFormula(storm::logic::GloballyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                // The formula is transformed to an until formula for the complementary event.
 | 
				
			|||
                auto negatedSubformula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, formula.getSubformula().asSharedPointer()); | 
				
			|||
                 | 
				
			|||
                preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), negatedSubformula), opInfo, data); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                if (formula.isReachabilityProbabilityFormula()){ | 
				
			|||
                    preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), formula.getSubformula().asSharedPointer()), opInfo, data); | 
				
			|||
                    return; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Analyze the subformula
 | 
				
			|||
                storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(data.originalModel); | 
				
			|||
                storm::storage::BitVector subFormulaResult = mc.check(formula.getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                 | 
				
			|||
                // Create a memory structure that stores whether a target state has already been reached
 | 
				
			|||
                storm::storage::MemoryStructureBuilder<ValueType, RewardModelType> builder(2, data.originalModel); | 
				
			|||
                // Get a unique label that is not already present in the model
 | 
				
			|||
                std::string relevantStatesLabel = data.memoryLabelPrefix + "_obj" + std::to_string(data.objectives.size()) + "_relevant"; | 
				
			|||
                builder.setLabel(0, relevantStatesLabel); | 
				
			|||
                builder.setTransition(0, 0, ~subFormulaResult); | 
				
			|||
                builder.setTransition(0, 1, subFormulaResult); | 
				
			|||
                builder.setTransition(1, 1, storm::storage::BitVector(data.originalModel.getNumberOfStates(), true)); | 
				
			|||
                for (auto const& initState : data.originalModel.getInitialStates()) { | 
				
			|||
                    builder.setInitialMemoryState(initState, subFormulaResult.get(initState) ? 1 : 0); | 
				
			|||
                } | 
				
			|||
                storm::storage::MemoryStructure objectiveMemory = builder.build(); | 
				
			|||
                data.memory = std::make_shared<storm::storage::MemoryStructure>(data.memory->product(objectiveMemory)); | 
				
			|||
                 | 
				
			|||
                auto relevantStatesFormula = std::make_shared<storm::logic::AtomicLabelFormula>(relevantStatesLabel); | 
				
			|||
                 | 
				
			|||
                std::string auxRewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size()); | 
				
			|||
                auto totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, auxRewardModelName, opInfo); | 
				
			|||
                data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                data.upperResultBoundObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                 | 
				
			|||
                if (formula.isReachabilityRewardFormula()) { | 
				
			|||
                    assert(optionalRewardModelName.is_initialized()); | 
				
			|||
                    data.tasks.push_back(std::make_shared<SparseMultiObjectivePreprocessorReachRewToTotalRewTask<SparseModelType>>(data.objectives.back(), relevantStatesFormula, optionalRewardModelName.get())); | 
				
			|||
                } else if (formula.isReachabilityTimeFormula() && data.originalModel.isOfType(storm::models::ModelType::MarkovAutomaton)) { | 
				
			|||
                    data.tasks.push_back(std::make_shared<SparseMultiObjectivePreprocessorReachTimeToTotalRewTask<SparseModelType>>(data.objectives.back(), relevantStatesFormula)); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The formula " << formula << " neither considers reachability probabilities nor reachability rewards " << (data.originalModel.isOfType(storm::models::ModelType::MarkovAutomaton) ?  "nor reachability time" : "") << ". This is not supported."); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                STORM_LOG_THROW(data.originalModel.isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidPropertyException, "Cumulative reward formulas are not supported for the given model type."); | 
				
			|||
                 | 
				
			|||
                auto cumulativeRewardFormula = std::make_shared<storm::logic::CumulativeRewardFormula>(formula); | 
				
			|||
                data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(cumulativeRewardFormula, *optionalRewardModelName, opInfo); | 
				
			|||
                bool onlyRewardBounds = true; | 
				
			|||
                for (uint64_t i = 0; i < cumulativeRewardFormula->getDimension(); ++i) { | 
				
			|||
                    if (!cumulativeRewardFormula->getTimeBoundReference(i).isRewardBound()) { | 
				
			|||
                        onlyRewardBounds = false; | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                if (onlyRewardBounds) { | 
				
			|||
                    data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                    data.upperResultBoundObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTotalRewardFormula(storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                 | 
				
			|||
                auto totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, *optionalRewardModelName, opInfo); | 
				
			|||
                data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                data.upperResultBoundObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::buildResult(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data, std::shared_ptr<SparseModelType> const& preprocessedModel, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                         | 
				
			|||
                ReturnType result(originalFormula, originalModel); | 
				
			|||
                 | 
				
			|||
                result.preprocessedModel = preprocessedModel; | 
				
			|||
                 | 
				
			|||
                for (auto& obj : data.objectives) { | 
				
			|||
                    result.objectives.push_back(std::move(*obj)); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                result.queryType = getQueryType(result.objectives); | 
				
			|||
                 | 
				
			|||
                setReward0States(result, backwardTransitions); | 
				
			|||
                checkRewardFiniteness(result, data.finiteRewardCheckObjectives, backwardTransitions); | 
				
			|||
                 | 
				
			|||
                // We compute upper result bounds if the 'sound' option has been enabled
 | 
				
			|||
                if (storm::settings::getModule<storm::settings::modules::GeneralSettings>().isSoundSet()) { | 
				
			|||
                    for (auto const& objIndex : data.upperResultBoundObjectives) { | 
				
			|||
                        result.objectives[objIndex].upperResultBound = computeUpperResultBound(result, objIndex, backwardTransitions); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                return result; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType::QueryType SparseMultiObjectivePreprocessor<SparseModelType>::getQueryType(std::vector<Objective<ValueType>> const& objectives) { | 
				
			|||
                uint_fast64_t numOfObjectivesWithThreshold = 0; | 
				
			|||
                for (auto& obj : objectives) { | 
				
			|||
                    if (obj.formula->hasBound()) { | 
				
			|||
                        ++numOfObjectivesWithThreshold; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                if (numOfObjectivesWithThreshold == objectives.size()) { | 
				
			|||
                    return ReturnType::QueryType::Achievability; | 
				
			|||
                } else if (numOfObjectivesWithThreshold + 1 == objectives.size()) { | 
				
			|||
                    // Note: We do not want to consider a Pareto query when the total number of objectives is one.
 | 
				
			|||
                    return ReturnType::QueryType::Quantitative; | 
				
			|||
                } else if (numOfObjectivesWithThreshold == 0) { | 
				
			|||
                    return ReturnType::QueryType::Pareto; | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Invalid Multi-objective query: The numer of qualitative objectives should be either 0 (Pareto query), 1 (quantitative query), or #objectives (achievability query)."); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::setReward0States(ReturnType& result, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                 | 
				
			|||
                uint_fast64_t stateCount = result.preprocessedModel->getNumberOfStates(); | 
				
			|||
                auto const& transitions = result.preprocessedModel->getTransitionMatrix(); | 
				
			|||
                std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices(); | 
				
			|||
                storm::storage::BitVector allStates(stateCount, true); | 
				
			|||
 | 
				
			|||
                // Get the choices that yield non-zero reward
 | 
				
			|||
                storm::storage::BitVector zeroRewardChoices(result.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                for (auto const& obj : result.objectives) { | 
				
			|||
                    if (obj.formula->isRewardOperatorFormula()) { | 
				
			|||
                        auto const& rewModel = result.preprocessedModel->getRewardModel(obj.formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                        zeroRewardChoices &= rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // Get the states that have reward for at least one (or for all) choices assigned to it.
 | 
				
			|||
                storm::storage::BitVector statesWithRewardForOneChoice = storm::storage::BitVector(stateCount, false); | 
				
			|||
                storm::storage::BitVector statesWithRewardForAllChoices = storm::storage::BitVector(stateCount, true); | 
				
			|||
                for (uint_fast64_t state = 0; state < stateCount; ++state) { | 
				
			|||
                    bool stateHasChoiceWithReward = false; | 
				
			|||
                    bool stateHasChoiceWithoutReward = false; | 
				
			|||
                    uint_fast64_t const& groupEnd = groupIndices[state + 1]; | 
				
			|||
                    for (uint_fast64_t choice = groupIndices[state]; choice < groupEnd; ++choice) { | 
				
			|||
                        if (zeroRewardChoices.get(choice)) { | 
				
			|||
                            stateHasChoiceWithoutReward = true; | 
				
			|||
                        } else { | 
				
			|||
                            stateHasChoiceWithReward = true; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (stateHasChoiceWithReward) { | 
				
			|||
                        statesWithRewardForOneChoice.set(state, true); | 
				
			|||
                    } | 
				
			|||
                    if (stateHasChoiceWithoutReward) { | 
				
			|||
                        statesWithRewardForAllChoices.set(state, false); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                // get the states for which there is a scheduler yielding reward zero
 | 
				
			|||
                result.reward0EStates = storm::utility::graph::performProbGreater0A(transitions, groupIndices, backwardTransitions, allStates, statesWithRewardForAllChoices, false, 0, zeroRewardChoices); | 
				
			|||
                result.reward0EStates.complement(); | 
				
			|||
                result.reward0AStates = storm::utility::graph::performProb0A(backwardTransitions, allStates, statesWithRewardForOneChoice); | 
				
			|||
                assert(result.reward0AStates.isSubsetOf(result.reward0EStates)); | 
				
			|||
            } | 
				
			|||
          | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            void SparseMultiObjectivePreprocessor<SparseModelType>::checkRewardFiniteness(ReturnType& result, storm::storage::BitVector const& finiteRewardCheckObjectives, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                 | 
				
			|||
                result.rewardFinitenessType = ReturnType::RewardFinitenessType::AllFinite; | 
				
			|||
                 | 
				
			|||
                auto const& transitions = result.preprocessedModel->getTransitionMatrix(); | 
				
			|||
                std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices(); | 
				
			|||
                 | 
				
			|||
                storm::storage::BitVector maxRewardsToCheck(result.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                storm::storage::BitVector minRewardsToCheck(result.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                for (auto const& objIndex : finiteRewardCheckObjectives) { | 
				
			|||
                    STORM_LOG_ASSERT(result.objectives[objIndex].formula->isRewardOperatorFormula(), "Objective needs to be checked for finite reward but has no reward operator."); | 
				
			|||
                    auto const& rewModel = result.preprocessedModel->getRewardModel(result.objectives[objIndex].formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                    auto unrelevantChoices = rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                    // For (upper) reward bounded cumulative reward formulas, we do not need to consider the choices where boundReward is collected.
 | 
				
			|||
                    if (result.objectives[objIndex].formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                        auto const& timeBoundReference = result.objectives[objIndex].formula->getSubformula().asCumulativeRewardFormula().getTimeBoundReference(); | 
				
			|||
                        // Only reward bounded formulas need a finiteness check
 | 
				
			|||
                        assert(timeBoundReference.isRewardBound()); | 
				
			|||
                        auto const& rewModelOfBound = result.preprocessedModel->getRewardModel(timeBoundReference.getRewardName()); | 
				
			|||
                        unrelevantChoices |= ~rewModelOfBound.getChoicesWithZeroReward(transitions); | 
				
			|||
                    } | 
				
			|||
                    if (storm::solver::minimize(result.objectives[objIndex].formula->getOptimalityType())) { | 
				
			|||
                        minRewardsToCheck &= unrelevantChoices; | 
				
			|||
                    } else { | 
				
			|||
                        maxRewardsToCheck &= unrelevantChoices; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                maxRewardsToCheck.complement(); | 
				
			|||
                minRewardsToCheck.complement(); | 
				
			|||
                 | 
				
			|||
                // Check reward finiteness under all schedulers
 | 
				
			|||
                storm::storage::BitVector allStates(result.preprocessedModel->getNumberOfStates(), true); | 
				
			|||
                if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, maxRewardsToCheck | minRewardsToCheck)) { | 
				
			|||
                    // Check whether there is a scheduler yielding infinite reward for a maximizing objective
 | 
				
			|||
                    if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, maxRewardsToCheck)) { | 
				
			|||
                        result.rewardFinitenessType = ReturnType::RewardFinitenessType::Infinite; | 
				
			|||
                    } else { | 
				
			|||
                        // Check whether there is a scheduler under which all rewards are finite.
 | 
				
			|||
                        result.rewardLessInfinityEStates = storm::utility::graph::performProb1E(transitions, groupIndices, backwardTransitions, allStates, result.reward0EStates); | 
				
			|||
                        if ((result.rewardLessInfinityEStates.get() & result.preprocessedModel->getInitialStates()).empty()) { | 
				
			|||
                            // There is no scheduler that induces finite reward for the initial state
 | 
				
			|||
                            result.rewardFinitenessType = ReturnType::RewardFinitenessType::Infinite; | 
				
			|||
                        } else { | 
				
			|||
                            result.rewardFinitenessType = ReturnType::RewardFinitenessType::ExistsParetoFinite; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                } else { | 
				
			|||
                    result.rewardLessInfinityEStates = allStates; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
         | 
				
			|||
            template<typename SparseModelType> | 
				
			|||
            boost::optional<typename SparseModelType::ValueType> SparseMultiObjectivePreprocessor<SparseModelType>::computeUpperResultBound(ReturnType const& result, uint64_t objIndex, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                boost::optional<ValueType> upperBound; | 
				
			|||
                 | 
				
			|||
                if (!result.originalModel.isOfType(storm::models::ModelType::Mdp)) { | 
				
			|||
                    return upperBound; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                auto const& transitions = result.preprocessedModel->getTransitionMatrix(); | 
				
			|||
                 | 
				
			|||
                if (result.objectives[objIndex].formula->isRewardOperatorFormula()) { | 
				
			|||
                    auto const& rewModel = result.preprocessedModel->getRewardModel(result.objectives[objIndex].formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                    auto actionRewards = rewModel.getTotalRewardVector(transitions); | 
				
			|||
                     | 
				
			|||
                    if (result.objectives[objIndex].formula->getSubformula().isTotalRewardFormula() || result.objectives[objIndex].formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                        // We have to eliminate ECs here to treat zero-reward ECs
 | 
				
			|||
  | 
				
			|||
                        storm::storage::BitVector allStates(result.preprocessedModel->getNumberOfStates(), true); | 
				
			|||
                         | 
				
			|||
                        // Get the set of states from which no reward is reachable
 | 
				
			|||
                        auto nonZeroRewardStates = rewModel.getStatesWithZeroReward(transitions); | 
				
			|||
                        nonZeroRewardStates.complement(); | 
				
			|||
                        auto expRewGreater0EStates = storm::utility::graph::performProbGreater0E(backwardTransitions, allStates, nonZeroRewardStates); | 
				
			|||
                         | 
				
			|||
                        auto zeroRewardChoices = rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                         | 
				
			|||
                        auto ecElimRes = storm::transformer::EndComponentEliminator<ValueType>::transform(transitions, expRewGreater0EStates, zeroRewardChoices, ~allStates); | 
				
			|||
                         | 
				
			|||
                        allStates.resize(ecElimRes.matrix.getRowGroupCount()); | 
				
			|||
                        storm::storage::BitVector outStates(allStates.size(), false); | 
				
			|||
                        std::vector<ValueType> rew0StateProbs; | 
				
			|||
                        rew0StateProbs.reserve(ecElimRes.matrix.getRowCount()); | 
				
			|||
                        for (uint64_t state = 0; state < allStates.size(); ++ state) { | 
				
			|||
                            for (uint64_t choice = ecElimRes.matrix.getRowGroupIndices()[state]; choice < ecElimRes.matrix.getRowGroupIndices()[state + 1]; ++choice) { | 
				
			|||
                                // Check whether the choice lead to a state with expRew 0 in the original model
 | 
				
			|||
                                bool isOutChoice = false; | 
				
			|||
                                uint64_t originalModelChoice = ecElimRes.newToOldRowMapping[choice]; | 
				
			|||
                                for (auto const& entry : transitions.getRow(originalModelChoice)) { | 
				
			|||
                                    if (!expRewGreater0EStates.get(entry.getColumn())) { | 
				
			|||
                                        isOutChoice = true; | 
				
			|||
                                        outStates.set(state, true); | 
				
			|||
                                        rew0StateProbs.push_back(storm::utility::one<ValueType>() - ecElimRes.matrix.getRowSum(choice)); | 
				
			|||
                                        assert (!storm::utility::isZero(rew0StateProbs.back())); | 
				
			|||
                                        break; | 
				
			|||
                                    } | 
				
			|||
                                } | 
				
			|||
                                if (!isOutChoice) { | 
				
			|||
                                    rew0StateProbs.push_back(storm::utility::zero<ValueType>()); | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                         | 
				
			|||
                        // An upper reward bound can only be computed if it is below infinity
 | 
				
			|||
                        if (storm::utility::graph::performProb1A(ecElimRes.matrix, ecElimRes.matrix.getRowGroupIndices(), ecElimRes.matrix.transpose(true), allStates, outStates).full()) { | 
				
			|||
                             | 
				
			|||
                            std::vector<ValueType> rewards; | 
				
			|||
                            rewards.reserve(ecElimRes.matrix.getRowCount()); | 
				
			|||
                            for (auto row : ecElimRes.newToOldRowMapping) { | 
				
			|||
                                rewards.push_back(actionRewards[row]); | 
				
			|||
                            } | 
				
			|||
                             | 
				
			|||
                            storm::modelchecker::helper::BaierUpperRewardBoundsComputer<ValueType> baier(ecElimRes.matrix, rewards, rew0StateProbs); | 
				
			|||
                            if (upperBound) { | 
				
			|||
                                upperBound = std::min(upperBound.get(), baier.computeUpperBound()); | 
				
			|||
                            } else { | 
				
			|||
                                upperBound = baier.computeUpperBound(); | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                if (upperBound) { | 
				
			|||
                    STORM_LOG_INFO("Computed upper result bound " << upperBound.get() << " for objective " << *result.objectives[objIndex].formula << "."); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_WARN("Could not compute upper result bound for objective " << *result.objectives[objIndex].formula); | 
				
			|||
                } | 
				
			|||
                return upperBound; | 
				
			|||
 | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
             | 
				
			|||
            template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<double>>; | 
				
			|||
            template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<double>>; | 
				
			|||
             | 
				
			|||
            template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<storm::RationalNumber>>; | 
				
			|||
            template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -1,105 +0,0 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
#include <string> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formulas.h" | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessorResult.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessorTask.h" | 
				
			|||
#include "storm/storage/memorystructure/MemoryStructure.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
             | 
				
			|||
            /* | 
				
			|||
             * This class invokes the necessary preprocessing for the constraint based multi-objective model checking algorithm | 
				
			|||
             */ | 
				
			|||
            template <class SparseModelType> | 
				
			|||
            class SparseMultiObjectivePreprocessor { | 
				
			|||
            public: | 
				
			|||
                typedef typename SparseModelType::ValueType ValueType; | 
				
			|||
                typedef typename SparseModelType::RewardModelType RewardModelType; | 
				
			|||
                typedef SparseMultiObjectivePreprocessorResult<SparseModelType> ReturnType; | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Preprocesses the given model w.r.t. the given formulas | 
				
			|||
                 * @param originalModel The considered model | 
				
			|||
                 * @param originalFormula the considered formula. The subformulas should only contain one OperatorFormula at top level. | 
				
			|||
                 */ | 
				
			|||
                static ReturnType preprocess(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula); | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                 | 
				
			|||
                struct PreprocessorData { | 
				
			|||
                    SparseModelType const& originalModel; | 
				
			|||
                    std::vector<std::shared_ptr<Objective<ValueType>>> objectives; | 
				
			|||
                    std::vector<std::shared_ptr<SparseMultiObjectivePreprocessorTask<SparseModelType>>> tasks; | 
				
			|||
                    std::shared_ptr<storm::storage::MemoryStructure> memory; | 
				
			|||
                     | 
				
			|||
                    // Indices of the objectives that require a check for finite reward | 
				
			|||
                    storm::storage::BitVector finiteRewardCheckObjectives; | 
				
			|||
                     | 
				
			|||
                    // Indices of the objectives for which we need to compute an upper bound for the result | 
				
			|||
                    storm::storage::BitVector upperResultBoundObjectives; | 
				
			|||
                     | 
				
			|||
                    std::string memoryLabelPrefix; | 
				
			|||
                    std::string rewardModelNamePrefix; | 
				
			|||
                     | 
				
			|||
                    PreprocessorData(SparseModelType const& model); | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Apply the neccessary preprocessing for the given formula. | 
				
			|||
                 * @param formula the current (sub)formula | 
				
			|||
                 * @param opInfo the information of the resulting operator formula | 
				
			|||
                 * @param data the current data. The currently processed objective is located at data.objectives.back() | 
				
			|||
                 * @param optionalRewardModelName the reward model name that is considered for the formula (if available) | 
				
			|||
                 */ | 
				
			|||
                static void preprocessOperatorFormula(storm::logic::OperatorFormula const& formula, PreprocessorData& data); | 
				
			|||
                static void preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                static void preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                static void preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                static void preprocessUntilFormula(storm::logic::UntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, std::shared_ptr<storm::logic::Formula const> subformula = nullptr); | 
				
			|||
                static void preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                static void preprocessGloballyFormula(storm::logic::GloballyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                static void preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); | 
				
			|||
                static void preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); | 
				
			|||
                static void preprocessTotalRewardFormula(storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); // The total reward formula itself does not need to be provided as it is unique. | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Builds the result from preprocessing | 
				
			|||
                 */ | 
				
			|||
                static ReturnType buildResult(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data, std::shared_ptr<SparseModelType> const& preprocessedModel, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Returns the query type | 
				
			|||
                 */ | 
				
			|||
                 static typename ReturnType::QueryType getQueryType(std::vector<Objective<ValueType>> const& objectives); | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Computes the set of states that have zero expected reward w.r.t. all expected reward objectives | 
				
			|||
                 */ | 
				
			|||
                static void setReward0States(ReturnType& result, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
 | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Checks whether the occurring expected rewards are finite and sets the RewardFinitenessType accordingly | 
				
			|||
                 * Returns the set of states for which a scheduler exists that induces finite reward for all objectives | 
				
			|||
                 */ | 
				
			|||
                static void checkRewardFiniteness(ReturnType& result, storm::storage::BitVector const& finiteRewardCheckObjectives, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
                 | 
				
			|||
                /*! | 
				
			|||
                 * Finds an upper bound for the expected reward of the objective with the given index (assuming it considers an expected reward objective) | 
				
			|||
                 */ | 
				
			|||
                static boost::optional<ValueType> computeUpperResultBound(ReturnType const& result, uint64_t objIndex, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
 | 
				
			|||
                 | 
				
			|||
            }; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -1,105 +0,0 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <vector> | 
				
			|||
#include <memory> | 
				
			|||
#include <boost/optional.hpp> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formulas.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/Objective.h" | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/UnexpectedException.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
             | 
				
			|||
            template <class SparseModelType> | 
				
			|||
            struct SparseMultiObjectivePreprocessorResult { | 
				
			|||
                 | 
				
			|||
                enum class QueryType { Achievability, Quantitative, Pareto }; | 
				
			|||
                enum class RewardFinitenessType { | 
				
			|||
                    AllFinite, // The expected reward is finite for all objectives and all schedulers | 
				
			|||
                    ExistsParetoFinite, // There is a Pareto optimal scheduler yielding finite rewards for all objectives | 
				
			|||
                    Infinite // All Pareto optimal schedulers yield infinite reward for at least one objective | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
                // Original data | 
				
			|||
                storm::logic::MultiObjectiveFormula const& originalFormula; | 
				
			|||
                SparseModelType const& originalModel; | 
				
			|||
                 | 
				
			|||
                // The preprocessed model and objectives | 
				
			|||
                std::shared_ptr<SparseModelType> preprocessedModel; | 
				
			|||
                std::vector<Objective<typename SparseModelType::ValueType>> objectives; | 
				
			|||
                 | 
				
			|||
                // Data about the query | 
				
			|||
                QueryType queryType; | 
				
			|||
                RewardFinitenessType rewardFinitenessType; | 
				
			|||
                 | 
				
			|||
                // The states of the preprocessed model for which... | 
				
			|||
                storm::storage::BitVector reward0EStates; // ... there is a scheduler such that all expected reward objectives have value zero | 
				
			|||
                storm::storage::BitVector reward0AStates; // ... all schedulers induce value 0 for all expected reward objectives | 
				
			|||
                boost::optional<storm::storage::BitVector> rewardLessInfinityEStates; // ... there is a scheduler yielding finite reward for all expected reward objectives | 
				
			|||
                // Note that other types of objectives (e.g., reward bounded reachability objectives) are not considered. | 
				
			|||
                 | 
				
			|||
                // Encodes a superset of the set of choices of preprocessedModel that are part of an end component (if given). | 
				
			|||
                //boost::optional<storm::storage::BitVector> ecChoicesHint; | 
				
			|||
                 | 
				
			|||
                SparseMultiObjectivePreprocessorResult(storm::logic::MultiObjectiveFormula const& originalFormula, SparseModelType const& originalModel) : originalFormula(originalFormula), originalModel(originalModel) { | 
				
			|||
                    // Intentionally left empty | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                bool containsOnlyTrivialObjectives() const { | 
				
			|||
                    // Trivial objectives are either total reward formulas or single-dimensional step or time bounded cumulative reward formulas | 
				
			|||
                    for (auto const& obj : objectives) { | 
				
			|||
                        if (obj.formula->isRewardOperatorFormula() && obj.formula->getSubformula().isTotalRewardFormula()) { | 
				
			|||
                            continue; | 
				
			|||
                        } | 
				
			|||
                        if (obj.formula->isRewardOperatorFormula() && obj.formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                            auto const& subf = obj.formula->getSubformula().asCumulativeRewardFormula(); | 
				
			|||
                            if (!subf.isMultiDimensional() && (subf.getTimeBoundReference().isTimeBound() || subf.getTimeBoundReference().isStepBound())) { | 
				
			|||
                                continue; | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                        // Reaching this point means that the objective is considered as non-trivial | 
				
			|||
                        return false; | 
				
			|||
                    } | 
				
			|||
                    return true; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                void printToStream(std::ostream& out) const { | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                    out << "                                                       Multi-objective Query                                              " << std::endl; | 
				
			|||
                    out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "Original Formula: " << std::endl; | 
				
			|||
                    out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                    out << "\t" << originalFormula << std::endl; | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "Objectives:" << std::endl; | 
				
			|||
                    out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                    for (auto const& obj : objectives) { | 
				
			|||
                        obj.printToStream(out); | 
				
			|||
                    } | 
				
			|||
                    out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "Original Model Information:" << std::endl; | 
				
			|||
                    originalModel.printModelInformationToStream(out); | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "Preprocessed Model Information:" << std::endl; | 
				
			|||
                    preprocessedModel->printModelInformationToStream(out); | 
				
			|||
                    out << std::endl; | 
				
			|||
                    out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                } | 
				
			|||
            | 
				
			|||
                friend std::ostream& operator<<(std::ostream& out, SparseMultiObjectivePreprocessorResult<SparseModelType> const& ret) { | 
				
			|||
                    ret.printToStream(out); | 
				
			|||
                    return out; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
            }; | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -1,137 +0,0 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <boost/optional.hpp> | 
				
			|||
#include <memory> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formula.h" | 
				
			|||
#include "storm/logic/Bound.h" | 
				
			|||
#include "storm/solver/OptimizationDirection.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/Objective.h" | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" | 
				
			|||
#include "storm/models/sparse/Mdp.h" | 
				
			|||
#include "storm/models/sparse/MarkovAutomaton.h" | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h" | 
				
			|||
#include "storm/utility/vector.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
             | 
				
			|||
            template <typename SparseModelType> | 
				
			|||
            class SparseMultiObjectivePreprocessorTask { | 
				
			|||
            public: | 
				
			|||
                SparseMultiObjectivePreprocessorTask(std::shared_ptr<Objective<typename SparseModelType::ValueType>> const& objective) : objective(objective) { | 
				
			|||
                    // intentionally left empty | 
				
			|||
                } | 
				
			|||
 | 
				
			|||
                virtual ~SparseMultiObjectivePreprocessorTask() = default; | 
				
			|||
 | 
				
			|||
                virtual void perform(SparseModelType& preprocessedModel) const = 0; | 
				
			|||
                 | 
				
			|||
                virtual bool requiresEndComponentAnalysis() const { | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
            protected: | 
				
			|||
                std::shared_ptr<Objective<typename SparseModelType::ValueType>> objective; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
            // Transforms reachability probabilities to total expected rewards by adding a rewardModel | 
				
			|||
            // such that one reward is given whenever a goal state is reached from a relevant state | 
				
			|||
            template <typename SparseModelType> | 
				
			|||
            class SparseMultiObjectivePreprocessorReachProbToTotalRewTask : public SparseMultiObjectivePreprocessorTask<SparseModelType> { | 
				
			|||
            public: | 
				
			|||
                SparseMultiObjectivePreprocessorReachProbToTotalRewTask(std::shared_ptr<Objective<typename SparseModelType::ValueType>> const& objective, std::shared_ptr<storm::logic::Formula const> const& relevantStateFormula, std::shared_ptr<storm::logic::Formula const> const& goalStateFormula) : SparseMultiObjectivePreprocessorTask<SparseModelType>(objective), relevantStateFormula(relevantStateFormula), goalStateFormula(goalStateFormula) { | 
				
			|||
                    // Intentionally left empty | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                virtual void perform(SparseModelType& preprocessedModel) const override  { | 
				
			|||
                        | 
				
			|||
                    // build stateAction reward vector that gives (one*transitionProbability) reward whenever a transition leads from a relevantState to a goalState | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(preprocessedModel); | 
				
			|||
                    storm::storage::BitVector relevantStates = mc.check(*relevantStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                    storm::storage::BitVector goalStates = mc.check(*goalStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                     | 
				
			|||
                    std::vector<typename SparseModelType::ValueType> objectiveRewards(preprocessedModel.getTransitionMatrix().getRowCount(), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                    for (auto const& state : relevantStates) { | 
				
			|||
                        for (uint_fast64_t row = preprocessedModel.getTransitionMatrix().getRowGroupIndices()[state]; row < preprocessedModel.getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) { | 
				
			|||
                            objectiveRewards[row] = preprocessedModel.getTransitionMatrix().getConstrainedRowSum(row, goalStates); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->isRewardOperatorFormula(), "No reward operator formula."); | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->asRewardOperatorFormula().hasRewardModelName(), "No reward model name has been specified"); | 
				
			|||
                    preprocessedModel.addRewardModel(this->objective->formula->asRewardOperatorFormula().getRewardModelName(), typename SparseModelType::RewardModelType(boost::none, std::move(objectiveRewards))); | 
				
			|||
                } | 
				
			|||
                         | 
				
			|||
            private: | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> relevantStateFormula; | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> goalStateFormula; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
            // Transforms expected reachability rewards to total expected rewards by adding a rewardModel | 
				
			|||
            // such that non-relevant states get reward zero | 
				
			|||
            template <typename SparseModelType> | 
				
			|||
            class SparseMultiObjectivePreprocessorReachRewToTotalRewTask : public SparseMultiObjectivePreprocessorTask<SparseModelType> { | 
				
			|||
            public: | 
				
			|||
                SparseMultiObjectivePreprocessorReachRewToTotalRewTask(std::shared_ptr<Objective<typename SparseModelType::ValueType>> const& objective, std::shared_ptr<storm::logic::Formula const> const& relevantStateFormula, std::string const& originalRewardModelName) : SparseMultiObjectivePreprocessorTask<SparseModelType>(objective), relevantStateFormula(relevantStateFormula), originalRewardModelName(originalRewardModelName) { | 
				
			|||
                    // Intentionally left empty | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                virtual void perform(SparseModelType& preprocessedModel) const override  { | 
				
			|||
                        | 
				
			|||
                    // build stateAction reward vector that only gives reward for relevant states | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(preprocessedModel); | 
				
			|||
                    storm::storage::BitVector nonRelevantStates = ~mc.check(*relevantStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                    typename SparseModelType::RewardModelType objectiveRewards = preprocessedModel.getRewardModel(originalRewardModelName); | 
				
			|||
                    objectiveRewards.reduceToStateBasedRewards(preprocessedModel.getTransitionMatrix(), false); | 
				
			|||
                    if (objectiveRewards.hasStateRewards()) { | 
				
			|||
                        storm::utility::vector::setVectorValues(objectiveRewards.getStateRewardVector(), nonRelevantStates, storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                    } | 
				
			|||
                    if (objectiveRewards.hasStateActionRewards()) { | 
				
			|||
                        for (auto state : nonRelevantStates) { | 
				
			|||
                            std::fill_n(objectiveRewards.getStateActionRewardVector().begin() + preprocessedModel.getTransitionMatrix().getRowGroupIndices()[state], preprocessedModel.getTransitionMatrix().getRowGroupSize(state), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->isRewardOperatorFormula(), "No reward operator formula."); | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->asRewardOperatorFormula().hasRewardModelName(), "No reward model name has been specified"); | 
				
			|||
                    preprocessedModel.addRewardModel(this->objective->formula->asRewardOperatorFormula().getRewardModelName(), std::move(objectiveRewards)); | 
				
			|||
                } | 
				
			|||
                         | 
				
			|||
            private: | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> relevantStateFormula; | 
				
			|||
                std::string originalRewardModelName; | 
				
			|||
            }; | 
				
			|||
                         | 
				
			|||
            // Transforms expected reachability time to total expected rewards by adding a rewardModel | 
				
			|||
            // such that every time step done from a relevant state yields one reward | 
				
			|||
            template <typename SparseModelType> | 
				
			|||
            class SparseMultiObjectivePreprocessorReachTimeToTotalRewTask : public SparseMultiObjectivePreprocessorTask<SparseModelType> { | 
				
			|||
            public: | 
				
			|||
                SparseMultiObjectivePreprocessorReachTimeToTotalRewTask(std::shared_ptr<Objective<typename SparseModelType::ValueType>> const& objective, std::shared_ptr<storm::logic::Formula const> const& relevantStateFormula) : SparseMultiObjectivePreprocessorTask<SparseModelType>(objective), relevantStateFormula(relevantStateFormula) { | 
				
			|||
                    // Intentionally left empty | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                virtual void perform(SparseModelType& preprocessedModel) const override  { | 
				
			|||
                        | 
				
			|||
                    // build stateAction reward vector that only gives reward for relevant states | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(preprocessedModel); | 
				
			|||
                    storm::storage::BitVector relevantStates = mc.check(*relevantStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                     | 
				
			|||
                    std::vector<typename SparseModelType::ValueType> timeRewards(preprocessedModel.getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                    storm::utility::vector::setVectorValues(timeRewards, dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(preprocessedModel).getMarkovianStates() & relevantStates, storm::utility::one<typename SparseModelType::ValueType>()); | 
				
			|||
 | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->isRewardOperatorFormula(), "No reward operator formula."); | 
				
			|||
                    STORM_LOG_ASSERT(this->objective->formula->asRewardOperatorFormula().hasRewardModelName(), "No reward model name has been specified"); | 
				
			|||
                    preprocessedModel.addRewardModel(this->objective->formula->asRewardOperatorFormula().getRewardModelName(), typename SparseModelType::RewardModelType(std::move(timeRewards))); | 
				
			|||
                } | 
				
			|||
                         | 
				
			|||
            private: | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> relevantStateFormula; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -0,0 +1,103 @@ | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h"
 | 
				
			|||
 | 
				
			|||
#include "storm/models/sparse/Mdp.h"
 | 
				
			|||
#include "storm/models/sparse/MarkovAutomaton.h"
 | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h"
 | 
				
			|||
#include "storm/storage/memorystructure/MemoryStructureBuilder.h"
 | 
				
			|||
#include "storm/storage/memorystructure/SparseModelMemoryProduct.h"
 | 
				
			|||
#include "storm/logic/Formulas.h"
 | 
				
			|||
#include "storm/logic/FragmentSpecification.h"
 | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | 
				
			|||
 | 
				
			|||
#include "storm/utility/macros.h"
 | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/NotImplementedException.h"
 | 
				
			|||
#include "storm/exceptions/NotSupportedException.h"
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
     | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                storm::storage::MemoryStructure getGoalMemory(SparseModelType const& model, storm::logic::Formula const& propositionalGoalStateFormula) { | 
				
			|||
                    STORM_LOG_THROW(propositionalGoalStateFormula.isInFragment(storm::logic::propositional()), storm::exceptions::NotSupportedException, "The  subformula " << propositionalGoalStateFormula << " should be propositional."); | 
				
			|||
                     | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(model); | 
				
			|||
                    storm::storage::BitVector goalStates = mc.check(propositionalGoalStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                 | 
				
			|||
                    // Check if the formula is already satisfied for all initial states. In such a case the trivial memory structure suffices.
 | 
				
			|||
                    if (model.getInitialStates().isSubsetOf(goalStates)) { | 
				
			|||
                        STORM_LOG_INFO("One objective is already satisfied for all initial states."); | 
				
			|||
                        return storm::storage::MemoryStructureBuilder<typename SparseModelType::ValueType, typename SparseModelType::RewardModelType>::buildTrivialMemoryStructure(model); | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                     | 
				
			|||
                    // Create a memory structure that stores whether a goal state has already been reached
 | 
				
			|||
                    storm::storage::MemoryStructureBuilder<typename SparseModelType::ValueType, typename SparseModelType::RewardModelType> builder(2, model); | 
				
			|||
                    builder.setTransition(0, 0, ~goalStates); | 
				
			|||
                    builder.setTransition(0, 1, goalStates); | 
				
			|||
                    builder.setTransition(1, 1, storm::storage::BitVector(model.getNumberOfStates(), true)); | 
				
			|||
                    for (auto const& initState : model.getInitialStates()) { | 
				
			|||
                        builder.setInitialMemoryState(initState, goalStates.get(initState) ? 1 : 0); | 
				
			|||
                    } | 
				
			|||
                    return builder.build(); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                storm::storage::MemoryStructure getUntilFormulaMemory(SparseModelType const& model, storm::logic::Formula const& leftSubFormula, storm::logic::Formula const& rightSubFormula) { | 
				
			|||
                    auto notLeftOrRight = std::make_shared<storm::logic::BinaryBooleanStateFormula>(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, | 
				
			|||
                                                std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, leftSubFormula.asSharedPointer()), | 
				
			|||
                                                rightSubFormula.asSharedPointer()); | 
				
			|||
                    return getGoalMemory<SparseModelType>(model, *notLeftOrRight); | 
				
			|||
                 | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                std::shared_ptr<SparseModelType> SparseMultiObjectiveMemoryIncorporation<SparseModelType>::incorporateGoalMemory(SparseModelType const& model, storm::logic::MultiObjectiveFormula const& formula) { | 
				
			|||
                    storm::storage::MemoryStructure memory = storm::storage::MemoryStructureBuilder<ValueType, RewardModelType>::buildTrivialMemoryStructure(model); | 
				
			|||
                     | 
				
			|||
                    for (auto const& subFormula : formula.getSubformulas()) { | 
				
			|||
                        STORM_LOG_THROW(subFormula->isOperatorFormula(), storm::exceptions::NotSupportedException, "The given Formula " << *subFormula << " is not supported."); | 
				
			|||
                        auto const& subsubFormula = subFormula->asOperatorFormula().getSubformula(); | 
				
			|||
                        if (subsubFormula.isEventuallyFormula()) { | 
				
			|||
                            memory = memory.product(getGoalMemory(model, subsubFormula.asEventuallyFormula().getSubformula())); | 
				
			|||
                        } else if (subsubFormula.isUntilFormula()) { | 
				
			|||
                            memory = memory.product(getUntilFormulaMemory(model, subsubFormula.asUntilFormula().getLeftSubformula(), subsubFormula.asUntilFormula().getRightSubformula())); | 
				
			|||
                        } else if (subsubFormula.isBoundedUntilFormula()) { | 
				
			|||
                            // For bounded formulas it is only reasonable to add the goal memory if it considers a single upper step/time bound.
 | 
				
			|||
                            auto const& buf = subsubFormula.asBoundedUntilFormula(); | 
				
			|||
                            if (!buf.isMultiDimensional() && !buf.getTimeBoundReference().isRewardBound() && (!buf.hasLowerBound() || (!buf.isLowerBoundStrict() && storm::utility::isZero(buf.template getLowerBound<storm::RationalNumber>())))) { | 
				
			|||
                                memory = memory.product(getUntilFormulaMemory(model, buf.getLeftSubformula(), buf.getRightSubformula())); | 
				
			|||
                            } | 
				
			|||
                        } else if (subsubFormula.isGloballyFormula()) { | 
				
			|||
                            auto notPhi = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, subsubFormula.asGloballyFormula().getSubformula().asSharedPointer()); | 
				
			|||
                            memory = memory.product(getGoalMemory(model, *notPhi)); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_THROW(subFormula->isOperatorFormula(), storm::exceptions::NotSupportedException, "The given Formula " << subsubFormula << " is not supported."); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
     | 
				
			|||
                    storm::storage::SparseModelMemoryProduct<ValueType> product = memory.product(model); | 
				
			|||
                    return std::dynamic_pointer_cast<SparseModelType>(product.build()); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                std::shared_ptr<SparseModelType> SparseMultiObjectiveMemoryIncorporation<SparseModelType>::incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates) { | 
				
			|||
                    STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "not implemented"); | 
				
			|||
                    return nullptr; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::Mdp<double>>; | 
				
			|||
                template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::MarkovAutomaton<double>>; | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::Mdp<storm::RationalNumber>>; | 
				
			|||
                template class SparseMultiObjectiveMemoryIncorporation<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; | 
				
			|||
                 | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
@ -0,0 +1,33 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
 | 
				
			|||
#include "storm/storage/memorystructure/MemoryStructure.h" | 
				
			|||
#include "storm/logic/MultiObjectiveFormula.h" | 
				
			|||
#include "storm/logic/Formula.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
             | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                class SparseMultiObjectiveMemoryIncorporation { | 
				
			|||
                 | 
				
			|||
                typedef typename SparseModelType::ValueType ValueType; | 
				
			|||
                typedef typename SparseModelType::RewardModelType RewardModelType; | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
     | 
				
			|||
                public: | 
				
			|||
                    static std::shared_ptr<SparseModelType> incorporateGoalMemory(SparseModelType const& model, storm::logic::MultiObjectiveFormula const& formula); | 
				
			|||
                    static std::shared_ptr<SparseModelType> incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates); | 
				
			|||
     | 
				
			|||
                }; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
@ -0,0 +1,424 @@ | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessor.h"
 | 
				
			|||
 | 
				
			|||
#include <algorithm>
 | 
				
			|||
#include <set>
 | 
				
			|||
 | 
				
			|||
#include "storm/models/sparse/Mdp.h"
 | 
				
			|||
#include "storm/models/sparse/MarkovAutomaton.h"
 | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h"
 | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h"
 | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | 
				
			|||
#include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h"
 | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | 
				
			|||
#include "storm/storage/MaximalEndComponentDecomposition.h"
 | 
				
			|||
#include "storm/storage/expressions/ExpressionManager.h"
 | 
				
			|||
#include "storm/transformer/EndComponentEliminator.h"
 | 
				
			|||
#include "storm/utility/macros.h"
 | 
				
			|||
#include "storm/utility/vector.h"
 | 
				
			|||
#include "storm/utility/graph.h"
 | 
				
			|||
#include "storm/settings/SettingsManager.h"
 | 
				
			|||
#include "storm/settings/modules/GeneralSettings.h"
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/InvalidPropertyException.h"
 | 
				
			|||
#include "storm/exceptions/UnexpectedException.h"
 | 
				
			|||
#include "storm/exceptions/NotImplementedException.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::preprocess(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula) { | 
				
			|||
                     | 
				
			|||
                    auto model = SparseMultiObjectiveMemoryIncorporation<SparseModelType>::incorporateGoalMemory(originalModel, originalFormula); | 
				
			|||
                    PreprocessorData data(model); | 
				
			|||
                     | 
				
			|||
                    //Invoke preprocessing on the individual objectives
 | 
				
			|||
                    for (auto const& subFormula : originalFormula.getSubformulas()) { | 
				
			|||
                        STORM_LOG_INFO("Preprocessing objective " << *subFormula<< "."); | 
				
			|||
                        data.objectives.push_back(std::make_shared<Objective<ValueType>>()); | 
				
			|||
                        data.objectives.back()->originalFormula = subFormula; | 
				
			|||
                        data.finiteRewardCheckObjectives.resize(data.objectives.size(), false); | 
				
			|||
                        data.upperResultBoundObjectives.resize(data.objectives.size(), false); | 
				
			|||
                        if (data.objectives.back()->originalFormula->isOperatorFormula()) { | 
				
			|||
                            preprocessOperatorFormula(data.objectives.back()->originalFormula->asOperatorFormula(), data); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Could not preprocess the subformula " << *subFormula << " of " << originalFormula << " because it is not supported"); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Remove reward models that are not needed anymore
 | 
				
			|||
                    std::set<std::string> relevantRewardModels; | 
				
			|||
                    for (auto const& obj : data.objectives) { | 
				
			|||
                        obj->formula->gatherReferencedRewardModels(relevantRewardModels); | 
				
			|||
                    } | 
				
			|||
                    data.model->restrictRewardModels(relevantRewardModels); | 
				
			|||
                     | 
				
			|||
                    // Build the actual result
 | 
				
			|||
                    return buildResult(originalModel, originalFormula, data); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template <typename SparseModelType> | 
				
			|||
                SparseMultiObjectivePreprocessor<SparseModelType>::PreprocessorData::PreprocessorData(std::shared_ptr<SparseModelType> model) : model(model) { | 
				
			|||
                     | 
				
			|||
                    // The rewardModelNamePrefix should not be a prefix of a reward model name of the given model to ensure uniqueness of new reward model names
 | 
				
			|||
                    rewardModelNamePrefix = "obj"; | 
				
			|||
                    while (true) { | 
				
			|||
                        bool prefixIsUnique = true; | 
				
			|||
                        for (auto const& rewardModels : model->getRewardModels()) { | 
				
			|||
                            if (rewardModelNamePrefix.size() <= rewardModels.first.size()) { | 
				
			|||
                                if (std::mismatch(rewardModelNamePrefix.begin(), rewardModelNamePrefix.end(), rewardModels.first.begin()).first == rewardModelNamePrefix.end()) { | 
				
			|||
                                    prefixIsUnique = false; | 
				
			|||
                                    rewardModelNamePrefix = "_" + rewardModelNamePrefix; | 
				
			|||
                                    break; | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                        if (prefixIsUnique) { | 
				
			|||
                            break; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                storm::logic::OperatorInformation getOperatorInformation(storm::logic::OperatorFormula const& formula, bool considerComplementaryEvent) { | 
				
			|||
                    storm::logic::OperatorInformation opInfo; | 
				
			|||
                    if (formula.hasBound()) { | 
				
			|||
                        opInfo.bound = formula.getBound(); | 
				
			|||
                        // Invert the bound (if necessary)
 | 
				
			|||
                        if (considerComplementaryEvent) { | 
				
			|||
                            opInfo.bound->threshold = opInfo.bound->threshold.getManager().rational(storm::utility::one<storm::RationalNumber>()) - opInfo.bound->threshold; | 
				
			|||
                            switch (opInfo.bound->comparisonType) { | 
				
			|||
                                case storm::logic::ComparisonType::Greater: | 
				
			|||
                                    opInfo.bound->comparisonType = storm::logic::ComparisonType::Less; | 
				
			|||
                                    break; | 
				
			|||
                                case storm::logic::ComparisonType::GreaterEqual: | 
				
			|||
                                    opInfo.bound->comparisonType = storm::logic::ComparisonType::LessEqual; | 
				
			|||
                                    break; | 
				
			|||
                                case storm::logic::ComparisonType::Less: | 
				
			|||
                                    opInfo.bound->comparisonType = storm::logic::ComparisonType::Greater; | 
				
			|||
                                    break; | 
				
			|||
                                case storm::logic::ComparisonType::LessEqual: | 
				
			|||
                                    opInfo.bound->comparisonType = storm::logic::ComparisonType::GreaterEqual; | 
				
			|||
                                    break; | 
				
			|||
                                default: | 
				
			|||
                                    STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Current objective " << formula << " has unexpected comparison type"); | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                        if (storm::logic::isLowerBound(opInfo.bound->comparisonType)) { | 
				
			|||
                            opInfo.optimalityType = storm::solver::OptimizationDirection::Maximize; | 
				
			|||
                        } else { | 
				
			|||
                            opInfo.optimalityType = storm::solver::OptimizationDirection::Minimize; | 
				
			|||
                        } | 
				
			|||
                        STORM_LOG_WARN_COND(!formula.hasOptimalityType(), "Optimization direction of formula " << formula << " ignored as the formula also specifies a threshold."); | 
				
			|||
                    } else if (formula.hasOptimalityType()){ | 
				
			|||
                        opInfo.optimalityType = formula.getOptimalityType(); | 
				
			|||
                        // Invert the optimality type (if necessary)
 | 
				
			|||
                        if (considerComplementaryEvent) { | 
				
			|||
                            opInfo.optimalityType = storm::solver::invert(opInfo.optimalityType.get()); | 
				
			|||
                        } | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Objective " << formula << " does not specify whether to minimize or maximize"); | 
				
			|||
                    } | 
				
			|||
                    return opInfo; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessOperatorFormula(storm::logic::OperatorFormula const& formula, PreprocessorData& data) { | 
				
			|||
                     | 
				
			|||
                    Objective<ValueType>& objective = *data.objectives.back(); | 
				
			|||
                     | 
				
			|||
                    // Check whether the complementary event is considered
 | 
				
			|||
                    objective.considersComplementaryEvent = formula.isProbabilityOperatorFormula() && formula.getSubformula().isGloballyFormula(); | 
				
			|||
                     | 
				
			|||
                    // Extract the operator information from the formula and potentially invert it for the complementary event
 | 
				
			|||
                    storm::logic::OperatorInformation opInfo = getOperatorInformation(formula, objective.considersComplementaryEvent); | 
				
			|||
 | 
				
			|||
                    if (formula.isProbabilityOperatorFormula()){ | 
				
			|||
                        preprocessProbabilityOperatorFormula(formula.asProbabilityOperatorFormula(), opInfo, data); | 
				
			|||
                    } else if (formula.isRewardOperatorFormula()){ | 
				
			|||
                        preprocessRewardOperatorFormula(formula.asRewardOperatorFormula(), opInfo, data); | 
				
			|||
                    } else if (formula.isTimeOperatorFormula()){ | 
				
			|||
                        preprocessTimeOperatorFormula(formula.asTimeOperatorFormula(), opInfo, data); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Could not preprocess the objective " << formula << " because it is not supported"); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                     | 
				
			|||
                    // Probabilities are between zero and one
 | 
				
			|||
                    data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                    data.objectives.back()->upperResultBound = storm::utility::one<ValueType>(); | 
				
			|||
                     | 
				
			|||
                    if (formula.getSubformula().isUntilFormula()){ | 
				
			|||
                        preprocessUntilFormula(formula.getSubformula().asUntilFormula(), opInfo, data); | 
				
			|||
                    } else if (formula.getSubformula().isBoundedUntilFormula()){ | 
				
			|||
                        preprocessBoundedUntilFormula(formula.getSubformula().asBoundedUntilFormula(), opInfo, data); | 
				
			|||
                    } else if (formula.getSubformula().isGloballyFormula()){ | 
				
			|||
                        preprocessGloballyFormula(formula.getSubformula().asGloballyFormula(), opInfo, data); | 
				
			|||
                    } else if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                        preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
     | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                     | 
				
			|||
                    STORM_LOG_THROW((formula.hasRewardModelName() && data.model->hasRewardModel(formula.getRewardModelName())) | 
				
			|||
                                    || (!formula.hasRewardModelName() && data.model->hasUniqueRewardModel()), storm::exceptions::InvalidPropertyException, "The reward model is not unique or the formula " << formula << " does not specify an existing reward model."); | 
				
			|||
                     | 
				
			|||
                    std::string rewardModelName; | 
				
			|||
                    if (formula.hasRewardModelName()) { | 
				
			|||
                        rewardModelName = formula.getRewardModelName(); | 
				
			|||
                        STORM_LOG_THROW(data.model->hasRewardModel(rewardModelName), storm::exceptions::InvalidPropertyException, "The reward model specified by formula " << formula << " does not exist in the model"); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(data.model->hasUniqueRewardModel(), storm::exceptions::InvalidOperationException, "The formula " << formula << " does not specify a reward model name and the reward model is not unique."); | 
				
			|||
                        rewardModelName = data.model->getRewardModels().begin()->first; | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                     | 
				
			|||
                    if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                        preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data, rewardModelName); | 
				
			|||
                    } else if (formula.getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                        preprocessCumulativeRewardFormula(formula.getSubformula().asCumulativeRewardFormula(), opInfo, data, rewardModelName); | 
				
			|||
                    } else if (formula.getSubformula().isTotalRewardFormula()) { | 
				
			|||
                        preprocessTotalRewardFormula(opInfo, data, rewardModelName); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
     | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                    // Time formulas are only supported for Markov automata
 | 
				
			|||
                    STORM_LOG_THROW(data.model->isOfType(storm::models::ModelType::MarkovAutomaton), storm::exceptions::InvalidPropertyException, "Time operator formulas are only supported for Markov automata."); | 
				
			|||
                     | 
				
			|||
                    data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>(); | 
				
			|||
                     | 
				
			|||
                    if (formula.getSubformula().isEventuallyFormula()){ | 
				
			|||
                        preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported."); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessUntilFormula(storm::logic::UntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, std::shared_ptr<storm::logic::Formula const> subformula) { | 
				
			|||
                     | 
				
			|||
                    // Try to transform the formula to expected total (or cumulative) rewards
 | 
				
			|||
                     | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model); | 
				
			|||
                    storm::storage::BitVector rightSubformulaResult = mc.check(formula.getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                    // Check if the formula is already satisfied in the initial state because then the transformation to expected rewards will fail.
 | 
				
			|||
                    // TODO: Handle this case more properly
 | 
				
			|||
                    STORM_LOG_THROW((data.model->getInitialStates() & rightSubformulaResult).empty(), storm::exceptions::NotImplementedException, "The Probability for the objective " << *data.objectives.back()->originalFormula << " is always one as the rhs of the until formula is true in the initial state. This (trivial) case is currently not implemented."); | 
				
			|||
                     | 
				
			|||
                    // Whenever a state that violates the left subformula or satisfies the right subformula is reached, the objective is 'decided', i.e., no more reward should be collected from there
 | 
				
			|||
                    storm::storage::BitVector notLeftOrRight = mc.check(formula.getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                    notLeftOrRight.complement(); | 
				
			|||
                    notLeftOrRight |=rightSubformulaResult; | 
				
			|||
                     | 
				
			|||
                    // Get the states that are reachable from a notLeftOrRight state
 | 
				
			|||
                    storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false); | 
				
			|||
                    storm::storage::BitVector reachableFromGoal = storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), notLeftOrRight, allStates, noStates); | 
				
			|||
                    // Get the states that are reachable from an initial state, stopping at the states reachable from goal
 | 
				
			|||
                    storm::storage::BitVector reachableFromInit = storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), ~notLeftOrRight, reachableFromGoal); | 
				
			|||
                    // Exclude the actual notLeftOrRight states from the states that are reachable from init
 | 
				
			|||
                    reachableFromInit &= ~notLeftOrRight; | 
				
			|||
                    // If we can reach a state that is reachable from goal, but which is not a goal state, it means that the transformation to expected rewards is not possible.
 | 
				
			|||
                    if ((reachableFromInit & reachableFromGoal).empty()) { | 
				
			|||
                        STORM_LOG_INFO("Objective " << data.objectives.back()->originalFormula << " is transformed to an expected total/cumulative reward property."); | 
				
			|||
                        // Transform to expected total rewards:
 | 
				
			|||
                        // build stateAction reward vector that gives (one*transitionProbability) reward whenever a transition leads from a reachableFromInit state to a goalState
 | 
				
			|||
                        std::vector<typename SparseModelType::ValueType> objectiveRewards(data.model->getTransitionMatrix().getRowCount(), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                        for (auto const& state : reachableFromInit) { | 
				
			|||
                            for (uint_fast64_t row = data.model->getTransitionMatrix().getRowGroupIndices()[state]; row < data.model->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) { | 
				
			|||
                                objectiveRewards[row] = data.model->getTransitionMatrix().getConstrainedRowSum(row, rightSubformulaResult); | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                        std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size()); | 
				
			|||
                        data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(boost::none, std::move(objectiveRewards))); | 
				
			|||
                        if (subformula == nullptr) { | 
				
			|||
                            subformula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                        } | 
				
			|||
                        data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(subformula, rewardModelName, opInfo); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_INFO("Objective " << data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property."); | 
				
			|||
                        data.objectives.back()->formula =  std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                     | 
				
			|||
                    // Check how to handle this query
 | 
				
			|||
                    if (formula.isMultiDimensional() || formula.getTimeBoundReference().isRewardBound()) { | 
				
			|||
                        STORM_LOG_INFO("Objective " << data.objectives.back()->originalFormula << " is not transformed to an expected cumulative reward property."); | 
				
			|||
                        data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo); | 
				
			|||
                    } else if (!formula.hasLowerBound() || (!formula.isLowerBoundStrict() && storm::utility::isZero(formula.template getLowerBound<storm::RationalNumber>()))) { | 
				
			|||
                        std::shared_ptr<storm::logic::Formula const> subformula; | 
				
			|||
                        if (!formula.hasUpperBound()) { | 
				
			|||
                            // The formula is actually unbounded
 | 
				
			|||
                            subformula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_THROW(!data.model->isOfType(storm::models::ModelType::MarkovAutomaton) || formula.getTimeBoundReference().isTimeBound(), storm::exceptions::InvalidPropertyException, "Bounded until formulas for Markov Automata are only allowed when time bounds are considered."); | 
				
			|||
                            storm::logic::TimeBound bound(formula.isUpperBoundStrict(), formula.getUpperBound()); | 
				
			|||
                            subformula = std::make_shared<storm::logic::CumulativeRewardFormula>(bound, formula.getTimeBoundReference()); | 
				
			|||
                        } | 
				
			|||
                        preprocessUntilFormula(storm::logic::UntilFormula(formula.getLeftSubformula().asSharedPointer(), formula.getRightSubformula().asSharedPointer()), opInfo, data, subformula); | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Property " << formula << "is not supported"); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessGloballyFormula(storm::logic::GloballyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) { | 
				
			|||
                    // The formula is transformed to an until formula for the complementary event.
 | 
				
			|||
                    auto negatedSubformula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, formula.getSubformula().asSharedPointer()); | 
				
			|||
                     | 
				
			|||
                    preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), negatedSubformula), opInfo, data); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                    if (formula.isReachabilityProbabilityFormula()){ | 
				
			|||
                        preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), formula.getSubformula().asSharedPointer()), opInfo, data); | 
				
			|||
                        return; | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Analyze the subformula
 | 
				
			|||
                    storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model); | 
				
			|||
                    storm::storage::BitVector subFormulaResult = mc.check(formula.getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); | 
				
			|||
                     | 
				
			|||
                     | 
				
			|||
                    // Get the states that are reachable from a goal state
 | 
				
			|||
                    storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false); | 
				
			|||
                    storm::storage::BitVector reachableFromGoal = storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), subFormulaResult, allStates, noStates); | 
				
			|||
                    // Get the states that are reachable from an initial state, stopping at the states reachable from goal
 | 
				
			|||
                    storm::storage::BitVector reachableFromInit = storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), allStates, reachableFromGoal); | 
				
			|||
                    // Exclude the actual goal states from the states that are reachable from an initial state
 | 
				
			|||
                    reachableFromInit &= ~subFormulaResult; | 
				
			|||
                    // If we can reach a state that is reachable from goal but which is not a goal state, it means that the transformation to expected total rewards is not possible.
 | 
				
			|||
                    if ((reachableFromInit & reachableFromGoal).empty()) { | 
				
			|||
                        STORM_LOG_INFO("Objective " << data.objectives.back()->originalFormula << " is transformed to an expected total reward property."); | 
				
			|||
                        // Transform to expected total rewards:
 | 
				
			|||
                         | 
				
			|||
                        std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size()); | 
				
			|||
                        auto totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                        data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, rewardModelName, opInfo); | 
				
			|||
                         | 
				
			|||
                        if (formula.isReachabilityRewardFormula()) { | 
				
			|||
                            // build stateAction reward vector that only gives reward for states that are reachable from init
 | 
				
			|||
                            assert(optionalRewardModelName.is_initialized()); | 
				
			|||
                            typename SparseModelType::RewardModelType objectiveRewards = data.model->getRewardModel(optionalRewardModelName.get()); | 
				
			|||
                            objectiveRewards.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false); | 
				
			|||
                            if (objectiveRewards.hasStateRewards()) { | 
				
			|||
                                storm::utility::vector::setVectorValues(objectiveRewards.getStateRewardVector(), reachableFromGoal, storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                            } | 
				
			|||
                            if (objectiveRewards.hasStateActionRewards()) { | 
				
			|||
                                for (auto state : reachableFromGoal) { | 
				
			|||
                                    std::fill_n(objectiveRewards.getStateActionRewardVector().begin() + data.model->getTransitionMatrix().getRowGroupIndices()[state], data.model->getTransitionMatrix().getRowGroupSize(state), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                            data.model->addRewardModel(rewardModelName, std::move(objectiveRewards)); | 
				
			|||
                        } else if (formula.isReachabilityTimeFormula() && data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) { | 
				
			|||
                             | 
				
			|||
                            // build stateAction reward vector that only gives reward for relevant states
 | 
				
			|||
                            std::vector<typename SparseModelType::ValueType> timeRewards(data.model->getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>()); | 
				
			|||
                            storm::utility::vector::setVectorValues(timeRewards, dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(*data.model).getMarkovianStates() & reachableFromInit, storm::utility::one<typename SparseModelType::ValueType>()); | 
				
			|||
                            data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(timeRewards))); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The formula " << formula << " neither considers reachability probabilities nor reachability rewards " << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ?  "nor reachability time" : "") << ". This is not supported."); | 
				
			|||
                        } | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_INFO("Objective " << data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property."); | 
				
			|||
                        if (formula.isReachabilityRewardFormula()) { | 
				
			|||
                            assert(optionalRewardModelName.is_initialized()); | 
				
			|||
                            data.objectives.back()->formula =  std::make_shared<storm::logic::RewardOperatorFormula>(formula.asSharedPointer(), optionalRewardModelName.get(), opInfo); | 
				
			|||
                        } else if (formula.isReachabilityTimeFormula() && data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) { | 
				
			|||
                            data.objectives.back()->formula =  std::make_shared<storm::logic::TimeOperatorFormula>(formula.asSharedPointer(), opInfo); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The formula " << formula << " neither considers reachability probabilities nor reachability rewards " << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ?  "nor reachability time" : "") << ". This is not supported."); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                    STORM_LOG_THROW(data.model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidPropertyException, "Cumulative reward formulas are not supported for the given model type."); | 
				
			|||
                     | 
				
			|||
                    auto cumulativeRewardFormula = std::make_shared<storm::logic::CumulativeRewardFormula>(formula); | 
				
			|||
                    data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(cumulativeRewardFormula, *optionalRewardModelName, opInfo); | 
				
			|||
                    bool onlyRewardBounds = true; | 
				
			|||
                    for (uint64_t i = 0; i < cumulativeRewardFormula->getDimension(); ++i) { | 
				
			|||
                        if (!cumulativeRewardFormula->getTimeBoundReference(i).isRewardBound()) { | 
				
			|||
                            onlyRewardBounds = false; | 
				
			|||
                            break; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (onlyRewardBounds) { | 
				
			|||
                        data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTotalRewardFormula(storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName) { | 
				
			|||
                     | 
				
			|||
                    auto totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>(); | 
				
			|||
                    data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, *optionalRewardModelName, opInfo); | 
				
			|||
                    data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true); | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::buildResult(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data) { | 
				
			|||
                    ReturnType result(originalFormula, originalModel); | 
				
			|||
                    auto backwardTransitions = data.model->getBackwardTransitions(); | 
				
			|||
                    result.preprocessedModel = data.model; | 
				
			|||
                     | 
				
			|||
                    for (auto& obj : data.objectives) { | 
				
			|||
                        result.objectives.push_back(std::move(*obj)); | 
				
			|||
                    } | 
				
			|||
                    result.queryType = getQueryType(result.objectives); | 
				
			|||
                    result.maybeInfiniteRewardObjectives = std::move(data.finiteRewardCheckObjectives); | 
				
			|||
                     | 
				
			|||
                    return result; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType::QueryType SparseMultiObjectivePreprocessor<SparseModelType>::getQueryType(std::vector<Objective<ValueType>> const& objectives) { | 
				
			|||
                    uint_fast64_t numOfObjectivesWithThreshold = 0; | 
				
			|||
                    for (auto& obj : objectives) { | 
				
			|||
                        if (obj.formula->hasBound()) { | 
				
			|||
                            ++numOfObjectivesWithThreshold; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    if (numOfObjectivesWithThreshold == objectives.size()) { | 
				
			|||
                        return ReturnType::QueryType::Achievability; | 
				
			|||
                    } else if (numOfObjectivesWithThreshold + 1 == objectives.size()) { | 
				
			|||
                        // Note: We do not want to consider a Pareto query when the total number of objectives is one.
 | 
				
			|||
                        return ReturnType::QueryType::Quantitative; | 
				
			|||
                    } else if (numOfObjectivesWithThreshold == 0) { | 
				
			|||
                        return ReturnType::QueryType::Pareto; | 
				
			|||
                    } else { | 
				
			|||
                        STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Invalid Multi-objective query: The numer of qualitative objectives should be either 0 (Pareto query), 1 (quantitative query), or #objectives (achievability query)."); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<double>>; | 
				
			|||
                template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<double>>; | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<storm::RationalNumber>>; | 
				
			|||
                template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,105 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
#include <string> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formulas.h" | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessorResult.h" | 
				
			|||
#include "storm/storage/memorystructure/MemoryStructure.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
     | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                /* | 
				
			|||
                 * This class invokes the necessary preprocessing for the constraint based multi-objective model checking algorithm | 
				
			|||
                 */ | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                class SparseMultiObjectivePreprocessor { | 
				
			|||
                public: | 
				
			|||
                    typedef typename SparseModelType::ValueType ValueType; | 
				
			|||
                    typedef typename SparseModelType::RewardModelType RewardModelType; | 
				
			|||
                    typedef SparseMultiObjectivePreprocessorResult<SparseModelType> ReturnType; | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Preprocesses the given model w.r.t. the given formulas | 
				
			|||
                     * @param originalModel The considered model | 
				
			|||
                     * @param originalFormula the considered formula. The subformulas should only contain one OperatorFormula at top level. | 
				
			|||
                     */ | 
				
			|||
                    static ReturnType preprocess(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula); | 
				
			|||
                     | 
				
			|||
                private: | 
				
			|||
                     | 
				
			|||
                    struct PreprocessorData { | 
				
			|||
                        std::shared_ptr<SparseModelType> model; | 
				
			|||
                        std::vector<std::shared_ptr<Objective<ValueType>>> objectives; | 
				
			|||
                         | 
				
			|||
                        // Indices of the objectives that require a check for finite reward | 
				
			|||
                        storm::storage::BitVector finiteRewardCheckObjectives; | 
				
			|||
                         | 
				
			|||
                        // Indices of the objectives for which we need to compute an upper bound for the result | 
				
			|||
                        storm::storage::BitVector upperResultBoundObjectives; | 
				
			|||
                         | 
				
			|||
                        std::string rewardModelNamePrefix; | 
				
			|||
                         | 
				
			|||
                        PreprocessorData(std::shared_ptr<SparseModelType> model); | 
				
			|||
                    }; | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Apply the neccessary preprocessing for the given formula. | 
				
			|||
                     * @param formula the current (sub)formula | 
				
			|||
                     * @param opInfo the information of the resulting operator formula | 
				
			|||
                     * @param data the current data. The currently processed objective is located at data.objectives.back() | 
				
			|||
                     * @param optionalRewardModelName the reward model name that is considered for the formula (if available) | 
				
			|||
                     */ | 
				
			|||
                    static void preprocessOperatorFormula(storm::logic::OperatorFormula const& formula, PreprocessorData& data); | 
				
			|||
                    static void preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                    static void preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                    static void preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                    static void preprocessUntilFormula(storm::logic::UntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, std::shared_ptr<storm::logic::Formula const> subformula = nullptr); | 
				
			|||
                    static void preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                    static void preprocessGloballyFormula(storm::logic::GloballyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data); | 
				
			|||
                    static void preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); | 
				
			|||
                    static void preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula, storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); | 
				
			|||
                    static void preprocessTotalRewardFormula(storm::logic::OperatorInformation const& opInfo, PreprocessorData& data, boost::optional<std::string> const& optionalRewardModelName = boost::none); // The total reward formula itself does not need to be provided as it is unique. | 
				
			|||
                     | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Builds the result from preprocessing | 
				
			|||
                     */ | 
				
			|||
                    static ReturnType buildResult(SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data); | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Returns the query type | 
				
			|||
                     */ | 
				
			|||
                     static typename ReturnType::QueryType getQueryType(std::vector<Objective<ValueType>> const& objectives); | 
				
			|||
                     | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Computes the set of states that have zero expected reward w.r.t. all expected reward objectives | 
				
			|||
                     */ | 
				
			|||
                    static void setReward0States(ReturnType& result, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
     | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Checks whether the occurring expected rewards are finite and sets the RewardFinitenessType accordingly | 
				
			|||
                     * Returns the set of states for which a scheduler exists that induces finite reward for all objectives | 
				
			|||
                     */ | 
				
			|||
                    static void checkRewardFiniteness(ReturnType& result, storm::storage::BitVector const& finiteRewardCheckObjectives, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Finds an upper bound for the expected reward of the objective with the given index (assuming it considers an expected reward objective) | 
				
			|||
                     */ | 
				
			|||
                    static boost::optional<ValueType> computeUpperResultBound(ReturnType const& result, uint64_t objIndex, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
     | 
				
			|||
                     | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -0,0 +1,95 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <vector> | 
				
			|||
#include <memory> | 
				
			|||
#include <boost/optional.hpp> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formulas.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/Objective.h" | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/UnexpectedException.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                struct SparseMultiObjectivePreprocessorResult { | 
				
			|||
                     | 
				
			|||
                    enum class QueryType { Achievability, Quantitative, Pareto }; | 
				
			|||
                     | 
				
			|||
                    // Original data | 
				
			|||
                    storm::logic::MultiObjectiveFormula const& originalFormula; | 
				
			|||
                    SparseModelType const& originalModel; | 
				
			|||
                     | 
				
			|||
                    // The preprocessed model and objectives | 
				
			|||
                    std::shared_ptr<SparseModelType> preprocessedModel; | 
				
			|||
                    std::vector<Objective<typename SparseModelType::ValueType>> objectives; | 
				
			|||
                     | 
				
			|||
                    // Data about the query | 
				
			|||
                    QueryType queryType; | 
				
			|||
                     | 
				
			|||
                    // Indices of the objectives that can potentially yield infinite reward | 
				
			|||
                    storm::storage::BitVector maybeInfiniteRewardObjectives; | 
				
			|||
                     | 
				
			|||
                    SparseMultiObjectivePreprocessorResult(storm::logic::MultiObjectiveFormula const& originalFormula, SparseModelType const& originalModel) : originalFormula(originalFormula), originalModel(originalModel) { | 
				
			|||
                        // Intentionally left empty | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    bool containsOnlyTrivialObjectives() const { | 
				
			|||
                        // Trivial objectives are either total reward formulas or single-dimensional step or time bounded cumulative reward formulas | 
				
			|||
                        for (auto const& obj : objectives) { | 
				
			|||
                            if (obj.formula->isRewardOperatorFormula() && obj.formula->getSubformula().isTotalRewardFormula()) { | 
				
			|||
                                continue; | 
				
			|||
                            } | 
				
			|||
                            if (obj.formula->isRewardOperatorFormula() && obj.formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                                auto const& subf = obj.formula->getSubformula().asCumulativeRewardFormula(); | 
				
			|||
                                if (!subf.isMultiDimensional() && (subf.getTimeBoundReference().isTimeBound() || subf.getTimeBoundReference().isStepBound())) { | 
				
			|||
                                    continue; | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                            // Reaching this point means that the objective is considered as non-trivial | 
				
			|||
                            return false; | 
				
			|||
                        } | 
				
			|||
                        return true; | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    void printToStream(std::ostream& out) const { | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                        out << "                                                       Multi-objective Query                                              " << std::endl; | 
				
			|||
                        out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "Original Formula: " << std::endl; | 
				
			|||
                        out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                        out << "\t" << originalFormula << std::endl; | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "Objectives:" << std::endl; | 
				
			|||
                        out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                        for (auto const& obj : objectives) { | 
				
			|||
                            obj.printToStream(out); | 
				
			|||
                        } | 
				
			|||
                        out << "--------------------------------------------------------------" << std::endl; | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "Original Model Information:" << std::endl; | 
				
			|||
                        originalModel.printModelInformationToStream(out); | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "Preprocessed Model Information:" << std::endl; | 
				
			|||
                        preprocessedModel->printModelInformationToStream(out); | 
				
			|||
                        out << std::endl; | 
				
			|||
                        out << "---------------------------------------------------------------------------------------------------------------------------------------" << std::endl; | 
				
			|||
                    } | 
				
			|||
                | 
				
			|||
                    friend std::ostream& operator<<(std::ostream& out, SparseMultiObjectivePreprocessorResult<SparseModelType> const& ret) { | 
				
			|||
                        ret.printToStream(out); | 
				
			|||
                        return out; | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                }; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
@ -0,0 +1,230 @@ | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveRewardAnalysis.h"
 | 
				
			|||
 | 
				
			|||
#include <algorithm>
 | 
				
			|||
#include <set>
 | 
				
			|||
#include <storm/modelchecker/multiobjective/SparseMultiObjectivePreprocessorResult.h>
 | 
				
			|||
 | 
				
			|||
#include "storm/models/sparse/Mdp.h"
 | 
				
			|||
#include "storm/models/sparse/MarkovAutomaton.h"
 | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h"
 | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectiveMemoryIncorporation.h"
 | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | 
				
			|||
#include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h"
 | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | 
				
			|||
#include "storm/storage/MaximalEndComponentDecomposition.h"
 | 
				
			|||
#include "storm/storage/expressions/ExpressionManager.h"
 | 
				
			|||
#include "storm/transformer/EndComponentEliminator.h"
 | 
				
			|||
#include "storm/utility/macros.h"
 | 
				
			|||
#include "storm/utility/vector.h"
 | 
				
			|||
#include "storm/utility/graph.h"
 | 
				
			|||
#include "storm/settings/SettingsManager.h"
 | 
				
			|||
#include "storm/settings/modules/GeneralSettings.h"
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
#include "storm/exceptions/InvalidPropertyException.h"
 | 
				
			|||
#include "storm/exceptions/UnexpectedException.h"
 | 
				
			|||
#include "storm/exceptions/NotImplementedException.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                typename SparseMultiObjectiveRewardAnalysis<SparseModelType>::ReturnType SparseMultiObjectiveRewardAnalysis<SparseModelType>::analyze(storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult) { | 
				
			|||
                    ReturnType result; | 
				
			|||
                    auto backwardTransitions = preprocessorResult.preprocessedModel->getBackwardTransitions(); | 
				
			|||
                     | 
				
			|||
                    setReward0States(result, preprocessorResult, backwardTransitions); | 
				
			|||
                    checkRewardFiniteness(result, preprocessorResult, backwardTransitions); | 
				
			|||
                     | 
				
			|||
                    return result; | 
				
			|||
                } | 
				
			|||
                 | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectiveRewardAnalysis<SparseModelType>::setReward0States(ReturnType& result, storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                     | 
				
			|||
                    uint_fast64_t stateCount = preprocessorResult.preprocessedModel->getNumberOfStates(); | 
				
			|||
                    auto const& transitions = preprocessorResult.preprocessedModel->getTransitionMatrix(); | 
				
			|||
                    std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices(); | 
				
			|||
                    storm::storage::BitVector allStates(stateCount, true); | 
				
			|||
     | 
				
			|||
                    // Get the choices that yield non-zero reward
 | 
				
			|||
                    storm::storage::BitVector zeroRewardChoices(preprocessorResult.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                    for (auto const& obj : preprocessorResult.objectives) { | 
				
			|||
                        if (obj.formula->isRewardOperatorFormula()) { | 
				
			|||
                            STORM_LOG_WARN_COND(obj.formula->getSubformula().isTotalRewardFormula() || obj.formula->getSubformula().isCumulativeRewardFormula(), "Analyzing reachability reward formulas is not supported properly."); | 
				
			|||
                            auto const& rewModel = preprocessorResult.preprocessedModel->getRewardModel(obj.formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                            zeroRewardChoices &= rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // Get the states that have reward for at least one (or for all) choices assigned to it.
 | 
				
			|||
                    storm::storage::BitVector statesWithRewardForOneChoice = storm::storage::BitVector(stateCount, false); | 
				
			|||
                    storm::storage::BitVector statesWithRewardForAllChoices = storm::storage::BitVector(stateCount, true); | 
				
			|||
                    for (uint_fast64_t state = 0; state < stateCount; ++state) { | 
				
			|||
                        bool stateHasChoiceWithReward = false; | 
				
			|||
                        bool stateHasChoiceWithoutReward = false; | 
				
			|||
                        uint_fast64_t const& groupEnd = groupIndices[state + 1]; | 
				
			|||
                        for (uint_fast64_t choice = groupIndices[state]; choice < groupEnd; ++choice) { | 
				
			|||
                            if (zeroRewardChoices.get(choice)) { | 
				
			|||
                                stateHasChoiceWithoutReward = true; | 
				
			|||
                            } else { | 
				
			|||
                                stateHasChoiceWithReward = true; | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                        if (stateHasChoiceWithReward) { | 
				
			|||
                            statesWithRewardForOneChoice.set(state, true); | 
				
			|||
                        } | 
				
			|||
                        if (stateHasChoiceWithoutReward) { | 
				
			|||
                            statesWithRewardForAllChoices.set(state, false); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                     | 
				
			|||
                    // get the states for which there is a scheduler yielding reward zero
 | 
				
			|||
                    result.reward0EStates = storm::utility::graph::performProbGreater0A(transitions, groupIndices, backwardTransitions, allStates, statesWithRewardForAllChoices, false, 0, zeroRewardChoices); | 
				
			|||
                    result.reward0EStates.complement(); | 
				
			|||
                    result.reward0AStates = storm::utility::graph::performProb0A(backwardTransitions, allStates, statesWithRewardForOneChoice); | 
				
			|||
                    assert(result.reward0AStates.isSubsetOf(result.reward0EStates)); | 
				
			|||
                } | 
				
			|||
              | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectiveRewardAnalysis<SparseModelType>::checkRewardFiniteness(ReturnType& result, storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                     | 
				
			|||
                    result.rewardFinitenessType = RewardFinitenessType::AllFinite; | 
				
			|||
                     | 
				
			|||
                    auto const& transitions = preprocessorResult.preprocessedModel->getTransitionMatrix(); | 
				
			|||
                    std::vector<uint_fast64_t> const& groupIndices = transitions.getRowGroupIndices(); | 
				
			|||
                     | 
				
			|||
                    storm::storage::BitVector maxRewardsToCheck(preprocessorResult.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                    storm::storage::BitVector minRewardsToCheck(preprocessorResult.preprocessedModel->getNumberOfChoices(), true); | 
				
			|||
                    for (auto const& objIndex : preprocessorResult.maybeInfiniteRewardObjectives) { | 
				
			|||
                        STORM_LOG_ASSERT(preprocessorResult.objectives[objIndex].formula->isRewardOperatorFormula(), "Objective needs to be checked for finite reward but has no reward operator."); | 
				
			|||
                        auto const& rewModel = preprocessorResult.preprocessedModel->getRewardModel(preprocessorResult.objectives[objIndex].formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                        auto unrelevantChoices = rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                        // For (upper) reward bounded cumulative reward formulas, we do not need to consider the choices where boundReward is collected.
 | 
				
			|||
                        if (preprocessorResult.objectives[objIndex].formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                            auto const& timeBoundReference = preprocessorResult.objectives[objIndex].formula->getSubformula().asCumulativeRewardFormula().getTimeBoundReference(); | 
				
			|||
                            // Only reward bounded formulas need a finiteness check
 | 
				
			|||
                            assert(timeBoundReference.isRewardBound()); | 
				
			|||
                            auto const& rewModelOfBound = preprocessorResult.preprocessedModel->getRewardModel(timeBoundReference.getRewardName()); | 
				
			|||
                            unrelevantChoices |= ~rewModelOfBound.getChoicesWithZeroReward(transitions); | 
				
			|||
                        } | 
				
			|||
                        if (storm::solver::minimize(preprocessorResult.objectives[objIndex].formula->getOptimalityType())) { | 
				
			|||
                            minRewardsToCheck &= unrelevantChoices; | 
				
			|||
                        } else { | 
				
			|||
                            maxRewardsToCheck &= unrelevantChoices; | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                    maxRewardsToCheck.complement(); | 
				
			|||
                    minRewardsToCheck.complement(); | 
				
			|||
                     | 
				
			|||
                    // Check reward finiteness under all schedulers
 | 
				
			|||
                    storm::storage::BitVector allStates(preprocessorResult.preprocessedModel->getNumberOfStates(), true); | 
				
			|||
                    if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, maxRewardsToCheck | minRewardsToCheck)) { | 
				
			|||
                        // Check whether there is a scheduler yielding infinite reward for a maximizing objective
 | 
				
			|||
                        if (storm::utility::graph::checkIfECWithChoiceExists(transitions, backwardTransitions, allStates, maxRewardsToCheck)) { | 
				
			|||
                            result.rewardFinitenessType = RewardFinitenessType::Infinite; | 
				
			|||
                        } else { | 
				
			|||
                            // Check whether there is a scheduler under which all rewards are finite.
 | 
				
			|||
                            result.rewardLessInfinityEStates = storm::utility::graph::performProb1E(transitions, groupIndices, backwardTransitions, allStates, result.reward0EStates); | 
				
			|||
                            if ((result.rewardLessInfinityEStates.get() & preprocessorResult.preprocessedModel->getInitialStates()).empty()) { | 
				
			|||
                                // There is no scheduler that induces finite reward for the initial state
 | 
				
			|||
                                result.rewardFinitenessType = RewardFinitenessType::Infinite; | 
				
			|||
                            } else { | 
				
			|||
                                result.rewardFinitenessType = RewardFinitenessType::ExistsParetoFinite; | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                    } else { | 
				
			|||
                        result.rewardLessInfinityEStates = allStates; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
             | 
				
			|||
                template<typename SparseModelType> | 
				
			|||
                void SparseMultiObjectiveRewardAnalysis<SparseModelType>::computeUpperResultBound(SparseModelType const& model, storm::modelchecker::multiobjective::Objective<ValueType>& objective, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { | 
				
			|||
                    STORM_LOG_INFO_COND(!objective.upperResultBound.is_initialized(), "Tried to find an upper result bound for an objective, but a result bound is already there."); | 
				
			|||
                     | 
				
			|||
                    if (model.isOfType(storm::models::ModelType::Mdp)) { | 
				
			|||
                         | 
				
			|||
                        auto const& transitions = model.getTransitionMatrix(); | 
				
			|||
                         | 
				
			|||
                        if (objective.formula->isRewardOperatorFormula()) { | 
				
			|||
                            auto const& rewModel = model.getRewardModel(objective.formula->asRewardOperatorFormula().getRewardModelName()); | 
				
			|||
                            auto actionRewards = rewModel.getTotalRewardVector(transitions); | 
				
			|||
                             | 
				
			|||
                            if (objective.formula->getSubformula().isTotalRewardFormula() || objective.formula->getSubformula().isCumulativeRewardFormula()) { | 
				
			|||
                                // We have to eliminate ECs here to treat zero-reward ECs
 | 
				
			|||
          | 
				
			|||
                                storm::storage::BitVector allStates(model.getNumberOfStates(), true); | 
				
			|||
                                 | 
				
			|||
                                // Get the set of states from which no reward is reachable
 | 
				
			|||
                                auto nonZeroRewardStates = rewModel.getStatesWithZeroReward(transitions); | 
				
			|||
                                nonZeroRewardStates.complement(); | 
				
			|||
                                auto expRewGreater0EStates = storm::utility::graph::performProbGreater0E(backwardTransitions, allStates, nonZeroRewardStates); | 
				
			|||
                                 | 
				
			|||
                                auto zeroRewardChoices = rewModel.getChoicesWithZeroReward(transitions); | 
				
			|||
                                 | 
				
			|||
                                auto ecElimRes = storm::transformer::EndComponentEliminator<ValueType>::transform(transitions, expRewGreater0EStates, zeroRewardChoices, ~allStates); | 
				
			|||
                                 | 
				
			|||
                                allStates.resize(ecElimRes.matrix.getRowGroupCount()); | 
				
			|||
                                storm::storage::BitVector outStates(allStates.size(), false); | 
				
			|||
                                std::vector<ValueType> rew0StateProbs; | 
				
			|||
                                rew0StateProbs.reserve(ecElimRes.matrix.getRowCount()); | 
				
			|||
                                for (uint64_t state = 0; state < allStates.size(); ++ state) { | 
				
			|||
                                    for (uint64_t choice = ecElimRes.matrix.getRowGroupIndices()[state]; choice < ecElimRes.matrix.getRowGroupIndices()[state + 1]; ++choice) { | 
				
			|||
                                        // Check whether the choice lead to a state with expRew 0 in the original model
 | 
				
			|||
                                        bool isOutChoice = false; | 
				
			|||
                                        uint64_t originalModelChoice = ecElimRes.newToOldRowMapping[choice]; | 
				
			|||
                                        for (auto const& entry : transitions.getRow(originalModelChoice)) { | 
				
			|||
                                            if (!expRewGreater0EStates.get(entry.getColumn())) { | 
				
			|||
                                                isOutChoice = true; | 
				
			|||
                                                outStates.set(state, true); | 
				
			|||
                                                rew0StateProbs.push_back(storm::utility::one<ValueType>() - ecElimRes.matrix.getRowSum(choice)); | 
				
			|||
                                                assert (!storm::utility::isZero(rew0StateProbs.back())); | 
				
			|||
                                                break; | 
				
			|||
                                            } | 
				
			|||
                                        } | 
				
			|||
                                        if (!isOutChoice) { | 
				
			|||
                                            rew0StateProbs.push_back(storm::utility::zero<ValueType>()); | 
				
			|||
                                        } | 
				
			|||
                                    } | 
				
			|||
                                } | 
				
			|||
                                 | 
				
			|||
                                // An upper reward bound can only be computed if it is below infinity
 | 
				
			|||
                                if (storm::utility::graph::performProb1A(ecElimRes.matrix, ecElimRes.matrix.getRowGroupIndices(), ecElimRes.matrix.transpose(true), allStates, outStates).full()) { | 
				
			|||
                                     | 
				
			|||
                                    std::vector<ValueType> rewards; | 
				
			|||
                                    rewards.reserve(ecElimRes.matrix.getRowCount()); | 
				
			|||
                                    for (auto row : ecElimRes.newToOldRowMapping) { | 
				
			|||
                                        rewards.push_back(actionRewards[row]); | 
				
			|||
                                    } | 
				
			|||
                                     | 
				
			|||
                                    storm::modelchecker::helper::BaierUpperRewardBoundsComputer<ValueType> baier(ecElimRes.matrix, rewards, rew0StateProbs); | 
				
			|||
                                    if (objective.upperResultBound) { | 
				
			|||
                                        objective.upperResultBound = std::min(objective.upperResultBound.get(), baier.computeUpperBound()); | 
				
			|||
                                    } else { | 
				
			|||
                                        objective.upperResultBound = baier.computeUpperBound(); | 
				
			|||
                                    } | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                         | 
				
			|||
                        if (objective.upperResultBound) { | 
				
			|||
                            STORM_LOG_INFO("Computed upper result bound " << objective.upperResultBound.get() << " for objective " << *objective.formula << "."); | 
				
			|||
                        } else { | 
				
			|||
                            STORM_LOG_WARN("Could not compute upper result bound for objective " << *objective.formula); | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
     | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectiveRewardAnalysis<storm::models::sparse::Mdp<double>>; | 
				
			|||
                template class SparseMultiObjectiveRewardAnalysis<storm::models::sparse::MarkovAutomaton<double>>; | 
				
			|||
                 | 
				
			|||
                template class SparseMultiObjectiveRewardAnalysis<storm::models::sparse::Mdp<storm::RationalNumber>>; | 
				
			|||
                template class SparseMultiObjectiveRewardAnalysis<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>; | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,73 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <memory> | 
				
			|||
#include <string> | 
				
			|||
 | 
				
			|||
#include "storm/logic/Formulas.h" | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
#include "storm/storage/SparseMatrix.h" | 
				
			|||
#include "storm/modelchecker/multiobjective/preprocessing/SparseMultiObjectivePreprocessorResult.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
     | 
				
			|||
    namespace modelchecker { | 
				
			|||
        namespace multiobjective { | 
				
			|||
            namespace preprocessing { | 
				
			|||
                 | 
				
			|||
                 | 
				
			|||
                enum class RewardFinitenessType { | 
				
			|||
                    AllFinite, // The expected reward is finite for all objectives and all schedulers | 
				
			|||
                    ExistsParetoFinite, // There is a Pareto optimal scheduler yielding finite rewards for all objectives | 
				
			|||
                    Infinite // All Pareto optimal schedulers yield infinite reward for at least one objective | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
                /* | 
				
			|||
                 * This class performs some analysis task regarding the occurring expected reward objectives | 
				
			|||
                 */ | 
				
			|||
                template <class SparseModelType> | 
				
			|||
                class SparseMultiObjectiveRewardAnalysis { | 
				
			|||
                public: | 
				
			|||
                    typedef typename SparseModelType::ValueType ValueType; | 
				
			|||
                    typedef typename SparseModelType::RewardModelType RewardModelType; | 
				
			|||
                     | 
				
			|||
                    struct ReturnType { | 
				
			|||
                        RewardFinitenessType rewardFinitenessType; | 
				
			|||
                 | 
				
			|||
                        // The states of the preprocessed model for which... | 
				
			|||
                        storm::storage::BitVector reward0EStates; // ... there is a scheduler such that all expected reward objectives have value zero | 
				
			|||
                        storm::storage::BitVector reward0AStates; // ... all schedulers induce value 0 for all expected reward objectives | 
				
			|||
                        boost::optional<storm::storage::BitVector> rewardLessInfinityEStates; // ... there is a scheduler yielding finite reward for all expected reward objectives | 
				
			|||
                    }; | 
				
			|||
 | 
				
			|||
                    /*! | 
				
			|||
                     * Analyzes the reward objectives of the multi objective query | 
				
			|||
                     * @param preprocessorResult The result from preprocessing. Must only contain expected total reward or cumulative reward objectives. | 
				
			|||
                     */ | 
				
			|||
                    static ReturnType analyze(storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult); | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Tries to finds an upper bound for the expected reward of the objective (assuming it considers an expected total reward objective) | 
				
			|||
                     */ | 
				
			|||
                    static void computeUpperResultBound(SparseModelType const& model, storm::modelchecker::multiobjective::Objective<ValueType>& objective, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
                     | 
				
			|||
                private: | 
				
			|||
                    /*! | 
				
			|||
                     * Computes the set of states that have zero expected reward w.r.t. all expected total/cumulative reward objectives | 
				
			|||
                     */ | 
				
			|||
                    static void setReward0States(ReturnType& result, storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
     | 
				
			|||
                     | 
				
			|||
                    /*! | 
				
			|||
                     * Checks whether the occurring expected rewards are finite and sets the RewardFinitenessType accordingly | 
				
			|||
                     * Returns the set of states for which a scheduler exists that induces finite reward for all objectives | 
				
			|||
                     */ | 
				
			|||
                    static void checkRewardFiniteness(ReturnType& result, storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult<SparseModelType> const& preprocessorResult, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); | 
				
			|||
                     | 
				
			|||
                     | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue