#pragma once #include "storm/modelchecker/AbstractModelChecker.h" #include "storm/storage/dd/DdType.h" namespace storm { namespace dd { template class Bdd; template class Add; } namespace models { template class Model; namespace symbolic { template class Model; template class Dtmc; template class Mdp; template class StochasticTwoPlayerGame; } } namespace abstraction { class QualitativeResultMinMax; template class SymbolicQualitativeResultMinMax; template class QualitativeMdpResultMinMax; template class QualitativeGameResultMinMax; class StateSet; template class SymbolicStateSet; } namespace modelchecker { template class SymbolicMdpPrctlModelChecker; template class QuantitativeCheckResult; template class SymbolicQuantitativeCheckResult; template class AbstractAbstractionRefinementModelChecker : public AbstractModelChecker { public: typedef typename ModelType::ValueType ValueType; static const storm::dd::DdType DdType = ModelType::DdType; /*! * Constructs a model checker for the given model. */ explicit AbstractAbstractionRefinementModelChecker(); virtual ~AbstractAbstractionRefinementModelChecker(); /// Overridden methods from super class. virtual bool canHandle(CheckTask const& checkTask) const override; virtual std::unique_ptr computeUntilProbabilities(CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityProbabilities(CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; protected: /// -------- Methods that need to be overwritten/defined by implementations in subclasses. /// Determines whether the model checker can handle reachability rewards or only reachability probabilities. virtual bool supportsReachabilityRewards() const; /// Retrieves the name of the underlying method. virtual std::string const& getName() const = 0; /// Called before the abstraction refinement loop to give the implementation a time to set up auxiliary data. virtual void initializeAbstractionRefinement() = 0; /// Retrieves the abstract model. virtual std::shared_ptr> getAbstractModel() = 0; /// Retrieves the state sets corresponding to the constraint and target states. virtual std::pair, std::unique_ptr> getConstraintAndTargetStates(storm::models::Model const& abstractModel) = 0; /// Retrieves the index of the abstraction player. Must be in {1} for DTMCs and MDPs and in {1, 2} for games. virtual uint64_t getAbstractionPlayer() const = 0; /// Retrieves whether schedulers need to be computed. virtual bool requiresSchedulerSynthesis() const = 0; /// Refines the abstract model so that the next iteration obtains bounds that are at least as precise as /// current ones. virtual void refineAbstractModel() = 0; /// -------- Methods used to implement the abstraction refinement procedure. /// Performs the actual abstraction refinement loop. std::unique_ptr performAbstractionRefinement(); /// Computes lower and upper bounds on the abstract model and returns the bounds for the initial states. std::pair, std::unique_ptr> computeBounds(storm::models::Model const& abstractModel); /// Solves the current check task qualitatively, i.e. computes all states with probability 0/1. std::unique_ptr computeQualitativeResult(storm::models::Model const& abstractModel, storm::abstraction::StateSet const& constraintStates, storm::abstraction::StateSet const& targetStates); std::unique_ptr computeQualitativeResult(storm::models::symbolic::Model const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr> computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::Model const& abstractModel); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::symbolic::Model const& abstractModel); // Methods related to the quantitative solution. bool skipQuantitativeSolution(storm::models::Model const& abstractModel, storm::abstraction::QualitativeResultMinMax const& qualitativeResults); bool skipQuantitativeSolution(storm::models::symbolic::Model const& abstractModel, storm::abstraction::SymbolicQualitativeResultMinMax const& qualitativeResults); std::pair, std::unique_ptr> computeQuantitativeResult(storm::models::Model const& abstractModel, storm::abstraction::StateSet const& constraintStates, storm::abstraction::StateSet const& targetStates, storm::abstraction::QualitativeResultMinMax const& qualitativeResults); std::pair, std::unique_ptr> computeQuantitativeResult(storm::models::symbolic::Model const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, storm::abstraction::SymbolicQualitativeResultMinMax const& qualitativeResults); std::pair, std::unique_ptr> computeQuantitativeResult(storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, storm::abstraction::SymbolicQualitativeResultMinMax const& qualitativeResults); std::pair, std::unique_ptr> computeQuantitativeResult(storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, storm::abstraction::SymbolicQualitativeResultMinMax const& qualitativeResults); std::pair, std::unique_ptr> computeQuantitativeResult(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, storm::abstraction::SymbolicQualitativeResultMinMax const& qualitativeResults); void filterInitialStates(storm::models::Model const& abstractModel, std::pair, std::unique_ptr>& bounds); void filterInitialStates(storm::models::symbolic::Model const& abstractModel, std::pair, std::unique_ptr>& bounds); void printBoundsInformation(std::pair, std::unique_ptr>& bounds); void printBoundsInformation(SymbolicQuantitativeCheckResult const& lowerBounds, SymbolicQuantitativeCheckResult const& upperBounds); bool checkForResultAfterQuantitativeCheck(storm::models::Model const& abstractModel, bool lowerBounds, QuantitativeCheckResult const& result); std::unique_ptr computeReachabilityProbabilitiesHelper(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& prob1States, storm::dd::Add const& startValues); /// Tries to obtain the results from the bounds. If either of the two bounds is null, the result is assumed /// to be the non-null bound. If neither is null and the bounds are sufficiently close, the average of the /// bounds is returned. std::unique_ptr tryToObtainResultFromBounds(storm::models::Model const& model, std::pair, std::unique_ptr>& bounds); /// Checks whether the provided bounds are sufficiently close to terminate. bool boundsAreSufficientlyClose(std::pair, std::unique_ptr> const& bounds); /// Retrieves the average of the two bounds. This should only be used to derive the overall result when the /// bounds are sufficiently close. std::unique_ptr getAverageOfBounds(std::pair, std::unique_ptr> const& bounds); /// Methods to set/get the check task that is currently handled. void setCheckTask(CheckTask const& checkTask); CheckTask const& getCheckTask() const; /// Methods that retrieve which results shall be reused. bool getReuseQualitativeResults() const; bool getReuseQuantitativeResults() const; private: /// The check task that is currently handled. std::unique_ptr const> checkTask; /// A flag indicating whether to reuse the qualitative results. bool reuseQualitativeResults; /// A flag indicating whether to reuse the quantitative results. bool reuseQuantitativeResults; /// The last qualitative results. std::unique_ptr lastQualitativeResults; /// The last full results that were obtained. These results (if there are any) specify the lower and upper /// bounds for all states in the model. std::pair, std::unique_ptr> lastBounds; }; } }