#ifndef STORM_STORAGE_BISIMULATIONDECOMPOSITION_H_ #define STORM_STORAGE_BISIMULATIONDECOMPOSITION_H_ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/storage/sparse/StateType.h" #include "storm/storage/Decomposition.h" #include "storm/storage/StateBlock.h" #include "storm/storage/bisimulation/Partition.h" #include "storm/storage/bisimulation/BisimulationType.h" #include "storm/solver/OptimizationDirection.h" #include "storm/logic/Formulas.h" #include "storm/utility/constants.h" #include "storm/utility/ConstantsComparator.h" namespace storm { namespace logic { class Formula; } namespace storage { inline BisimulationType resolveBisimulationTypeChoice(BisimulationTypeChoice c) { switch(c) { case BisimulationTypeChoice::Strong: return BisimulationType::Strong; case BisimulationTypeChoice::Weak: return BisimulationType::Weak; case BisimulationTypeChoice::FromSettings: if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) { return BisimulationType::Weak; } else { return BisimulationType::Strong; } } return BisimulationType::Strong; } /*! * This class is the superclass of all decompositions of a sparse model into its bisimulation quotient. */ template <typename ModelType, typename BlockDataType> class BisimulationDecomposition : public Decomposition<StateBlock> { public: typedef typename ModelType::ValueType ValueType; typedef typename ModelType::RewardModelType RewardModelType; // A class that offers the possibility to customize the bisimulation. struct Options { // Creates an object representing the default values for all options. Options(); /*! * Creates an object representing the options necessary to obtain the quotient while still preserving * the given formula. * * @param The model for which the quotient model shall be computed. This needs to be given in order to * derive a suitable initial partition. * @param formula The formula that is to be preserved. */ Options(ModelType const& model, storm::logic::Formula const& formula); /*! * Creates an object representing the options necessary to obtain the smallest quotient while still * preserving the given formulas. * * @param The model for which the quotient model shall be computed. This needs to be given in order to * derive a suitable initial partition. * @param formulas The formulas that need to be preserved. */ Options(ModelType const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas); /*! * Changes the options in a way that the given formula is preserved. * * @param formula The only formula to check. */ void preserveFormula(storm::logic::Formula const& formula); /** * Sets the bisimulation type. If the bisimulation type is set to weak, * we also change the bounded flag (as bounded properties are not preserved under * weak bisimulation). */ void setType(BisimulationType t) { if(t == BisimulationType::Weak) { bounded = false; } type = t; } BisimulationType getType() const { return this->type; } bool getBounded() const { return this->bounded; } bool getKeepRewards() const { return this->keepRewards; } bool isOptimizationDirectionSet() const { return static_cast<bool>(optimalityType); } OptimizationDirection getOptimizationDirection() const { STORM_LOG_ASSERT(optimalityType, "Optimality type not set."); return optimalityType.get(); } // A flag that indicates whether a measure driven initial partition is to be used. If this flag is set // to true, the two optional pairs phiStatesAndLabel and psiStatesAndLabel must be set. Then, the // measure driven initial partition wrt. to the states phi and psi is taken. bool measureDrivenInitialPartition; boost::optional<storm::storage::BitVector> phiStates; boost::optional<storm::storage::BitVector> psiStates; /// An optional set of strings that indicate which of the atomic propositions of the model are to be /// respected and which may be ignored. If not given, all atomic propositions of the model are respected. boost::optional<std::set<std::string>> respectedAtomicPropositions; /// A flag that governs whether the quotient model is actually built or only the decomposition is computed. bool buildQuotient; private: boost::optional<OptimizationDirection> optimalityType; /// A flag that indicates whether or not the state-rewards of the model are to be respected (and should /// be kept in the quotient model, if one is built). bool keepRewards; /// A flag that indicates whether a strong or a weak bisimulation is to be computed. BisimulationType type; /// A flag that indicates whether step-bounded properties are to be preserved. This may only be set to tru /// when computing strong bisimulation equivalence. bool bounded; /*! * Sets the options under the assumption that the given formula is the only one that is to be checked. * * @param model The model for which to preserve the formula. * @param formula The only formula to check. */ void preserveSingleFormula(ModelType const& model, storm::logic::Formula const& formula); /*! * Adds the given expressions and labels to the set of respected atomic propositions. * * @param expressions The expressions to respect. * @param labels The labels to respect. */ void addToRespectedAtomicPropositions(std::vector<std::shared_ptr<storm::logic::AtomicExpressionFormula const>> const& expressions, std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>> const& labels); /* * Checks whether a measure driven partition is possible with the given formula and sets the necessary * data if this is the case. * * @param model The model for which to derive the data. * @param formula The formula for which to derive the data for the measure driven initial partition (if * applicable). */ void checkAndSetMeasureDrivenInitialPartition(ModelType const& model, storm::logic::Formula const& formula); }; /*! * Decomposes the given model into equivalance classes of a bisimulation. * * @param model The model to decompose. * @param options The options to use during for the decomposition. */ BisimulationDecomposition(ModelType const& model, Options const& options); virtual ~BisimulationDecomposition() = default; /*! * Retrieves the quotient of the model under the computed bisimulation. * * @return The quotient model. */ std::shared_ptr<ModelType> getQuotient() const; /*! * Computes the decomposition of the model into bisimulation equivalence classes. If requested, a quotient * model is built. */ void computeBisimulationDecomposition(); protected: /*! * Decomposes the given model into equivalance classes of a bisimulation. * * @param model The model to decompose. * @param backwardTransition The backward transitions of the model. * @param options The options to use during for the decomposition. */ BisimulationDecomposition(ModelType const& model, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, Options const& options); /*! * Performs the partition refinement on the model and thereby computes the equivalence classes under strong * bisimulation equivalence. If required, the quotient model is built and may be retrieved using * getQuotient(). */ void performPartitionRefinement(); /*! * Refines the partition by considering the given splitter. All blocks that become potential splitters * because of this refinement, are marked as splitters and inserted into the splitter vector. * * @param splitter The splitter to use. * @param splitterVector The vector into which to insert the newly discovered potential splitters. */ virtual void refinePartitionBasedOnSplitter(bisimulation::Block<BlockDataType>& splitter, std::vector<bisimulation::Block<BlockDataType>*>& splitterQueue) = 0; /*! * Builds the quotient model based on the previously computed equivalence classes (stored in the blocks * of the decomposition. */ virtual void buildQuotient() = 0; /*! * Initializes the initial partition based on all respected labels. */ virtual void initializeLabelBasedPartition(); /*! * Creates the measure-driven initial partition for reaching psi states from phi states. */ virtual void initializeMeasureDrivenPartition(); /*! * A function that can initialize auxiliary data structures. It is called after initializing the initial partition. */ virtual void initialize(); /*! * Computes the set of states with probability 0/1 for satisfying phi until psi. This is used for the measure * driven initial partition. * * @return The states with probability 0 and 1. */ virtual std::pair<storm::storage::BitVector, storm::storage::BitVector> getStatesWithProbability01() = 0; /*! * Splits the initial partition based on the (unique) reward model of the current model. */ virtual void splitInitialPartitionBasedOnRewards(); /*! * Splits the initial partition based on the given reward vector. */ virtual void splitInitialPartitionBasedOnRewards(std::vector<ValueType> const& rewardVector); /*! * Splits the initial partition based on the given vector of action rewards. */ virtual void splitInitialPartitionBasedOnActionRewards(std::vector<std::set<ValueType>> const& rewardVector); /*! * Constructs the blocks of the decomposition object based on the current partition. */ void extractDecompositionBlocks(); // The model to decompose. ModelType const& model; // The backward transitions of the model. storm::storage::SparseMatrix<ValueType> backwardTransitions; // The options used during construction. Options options; // The current partition (used by partition refinement). storm::storage::bisimulation::Partition<BlockDataType> partition; // A comparator used for comparing the distances of constants. storm::utility::ConstantsComparator<ValueType> comparator; // The quotient, if it was build. Otherwhise a null pointer. std::shared_ptr<ModelType> quotient; }; } } #endif /* STORM_STORAGE_BISIMULATIONDECOMPOSITION_H_ */