#ifndef STORM_MODELCHECKER_CHECKTASK_H_ #define STORM_MODELCHECKER_CHECKTASK_H_ #include <boost/optional.hpp> #include <memory> #include "storm/logic/Formulas.h" #include "storm/utility/constants.h" #include "storm/solver/OptimizationDirection.h" #include "storm/logic/ComparisonType.h" #include "storm/modelchecker/hints/ModelCheckerHint.h" #include "storm/exceptions/InvalidOperationException.h" namespace storm { namespace logic { class Formula; } namespace modelchecker { enum class CheckType { Probabilities, Rewards }; /* * This class is used to customize the checking process of a formula. */ template<typename FormulaType = storm::logic::Formula, typename ValueType = double> class CheckTask { public: template<typename OtherFormulaType, typename OtherValueType> friend class CheckTask; /*! * Creates a task object with the default options for the given formula. */ CheckTask(FormulaType const& formula, bool onlyInitialStatesRelevant = false) : formula(formula), hint(new ModelCheckerHint()) { this->onlyInitialStatesRelevant = onlyInitialStatesRelevant; this->produceSchedulers = false; this->qualitative = false; updateOperatorInformation(); } /*! * Copies the check task from the source while replacing the formula with the new one. In particular, this * changes the formula type of the check task object. */ template<typename NewFormulaType> CheckTask<NewFormulaType, ValueType> substituteFormula(NewFormulaType const& newFormula) const { CheckTask<NewFormulaType, ValueType> result(newFormula, this->optimizationDirection, this->rewardModel, this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint); result.updateOperatorInformation(); return result; } /*! * If the currently specified formula is an OperatorFormula, this method updates the information that is given in the Operator formula. * Calling this method has no effect if the provided formula is not an operator formula. */ void updateOperatorInformation() { if (formula.get().isOperatorFormula()) { storm::logic::OperatorFormula const& operatorFormula = formula.get().asOperatorFormula(); if (operatorFormula.hasOptimalityType()) { this->optimizationDirection = operatorFormula.getOptimalityType(); } if (operatorFormula.hasBound()) { this->bound = operatorFormula.getBound(); } if (operatorFormula.hasOptimalityType()) { this->optimizationDirection = operatorFormula.getOptimalityType(); } else if (operatorFormula.hasBound()) { this->optimizationDirection = operatorFormula.getComparisonType() == storm::logic::ComparisonType::Less || operatorFormula.getComparisonType() == storm::logic::ComparisonType::LessEqual ? OptimizationDirection::Maximize : OptimizationDirection::Minimize; } if (formula.get().isProbabilityOperatorFormula()) { storm::logic::ProbabilityOperatorFormula const& probabilityOperatorFormula = formula.get().asProbabilityOperatorFormula(); if (probabilityOperatorFormula.hasBound()) { if (storm::utility::isZero(probabilityOperatorFormula.template getThresholdAs<ValueType>()) || storm::utility::isOne(probabilityOperatorFormula.template getThresholdAs<ValueType>())) { this->qualitative = true; } } } else if (formula.get().isRewardOperatorFormula()) { storm::logic::RewardOperatorFormula const& rewardOperatorFormula = formula.get().asRewardOperatorFormula(); this->rewardModel = rewardOperatorFormula.getOptionalRewardModelName(); if (rewardOperatorFormula.hasBound()) { if (storm::utility::isZero(rewardOperatorFormula.template getThresholdAs<ValueType>())) { this->qualitative = true; } } } } } /*! * Copies the check task from the source while replacing the considered ValueType the new one. In particular, this * changes the formula type of the check task object. */ template<typename NewValueType> CheckTask<FormulaType, NewValueType> convertValueType() const { return CheckTask<FormulaType, NewValueType>(this->formula, this->optimizationDirection, this->rewardModel, this->onlyInitialStatesRelevant, this->bound, this->qualitative, this->produceSchedulers, this->hint); } /*! * Retrieves the formula from this task. */ FormulaType const& getFormula() const { return formula.get(); } /*! * Retrieves whether an optimization direction was set. */ bool isOptimizationDirectionSet() const { return static_cast<bool>(optimizationDirection); } /*! * Retrieves the optimization direction (if set). */ storm::OptimizationDirection const& getOptimizationDirection() const { return optimizationDirection.get(); } /*! * Sets the optimization direction. */ void setOptimizationDirection(storm::OptimizationDirection const& dir) { optimizationDirection = dir; } /*! * Retrieves whether a reward model was set. */ bool isRewardModelSet() const { return static_cast<bool>(rewardModel); } /*! * Retrieves the reward model over which to perform the checking (if set). */ std::string const& getRewardModel() const { return rewardModel.get(); } /*! * Retrieves whether only the initial states are relevant in the computation. */ bool isOnlyInitialStatesRelevantSet() const { return onlyInitialStatesRelevant; } /*! * Sets whether only initial states are relevant. */ CheckTask<FormulaType, ValueType>& setOnlyInitialStatesRelevant(bool value = true) { this->onlyInitialStatesRelevant = value; return *this; } /*! * Retrieves whether there is a bound with which the values for the states will be compared. */ bool isBoundSet() const { return static_cast<bool>(bound); } /*! * Retrieves the value of the bound (if set). */ ValueType getBoundThreshold() const { STORM_LOG_THROW(!bound.get().threshold.containsVariables(), storm::exceptions::InvalidOperationException, "Cannot evaluate threshold '" << bound.get().threshold << "' as it contains undefined constants."); return storm::utility::convertNumber<ValueType>(bound.get().threshold.evaluateAsRational()); } /*! * Retrieves the comparison type of the bound (if set). */ storm::logic::ComparisonType const& getBoundComparisonType() const { return bound.get().comparisonType; } /*! * Retrieves the bound (if set). */ storm::logic::Bound const& getBound() const { return bound.get(); } /*! * Retrieves the bound (if set). */ boost::optional<storm::logic::Bound> const& getOptionalBound() const { return bound; } /*! * Retrieves whether the computation only needs to be performed qualitatively, because the values will only * be compared to 0/1. */ bool isQualitativeSet() const { return qualitative; } /*! * sets whether the computation only needs to be performed qualitatively, because the values will only * be compared to 0/1. */ void setQualitative(bool value) { qualitative = value; } /*! * Sets whether to produce schedulers (if supported). */ void setProduceSchedulers(bool produceSchedulers = true) { this->produceSchedulers = produceSchedulers; } /*! * Retrieves whether scheduler(s) are to be produced (if supported). */ bool isProduceSchedulersSet() const { return produceSchedulers; } /*! * sets a hint that might contain information that speeds up the modelchecking process (if supported by the model checker) */ void setHint(std::shared_ptr<ModelCheckerHint> const& hint) { this->hint = hint; } /*! * Retrieves a hint that might contain information that speeds up the modelchecking process (if supported by the model checker) */ ModelCheckerHint const& getHint() const { return *hint; } ModelCheckerHint& getHint() { return *hint; } /*! * Conversion operator that strips the type of the formula. */ operator CheckTask<storm::logic::Formula, ValueType>() const { return this->substituteFormula<storm::logic::Formula>(this->getFormula()); } private: /*! * Creates a task object with the given options. * * @param formula The formula to attach to the task. * @param optimizationDirection If set, the probabilities will be minimized/maximized. * @param rewardModelName If given, the checking has to be done wrt. to this reward model. * @param onlyInitialStatesRelevant If set to true, the model checker may decide to only compute the values * for the initial states. * @param bound The bound with which the states will be compared. * @param qualitative A flag specifying whether the property needs to be checked qualitatively, i.e. compared * with bounds 0/1. * @param produceSchedulers If supported by the model checker and the model formalism, schedulers to achieve * a value will be produced if this flag is set. */ CheckTask(std::reference_wrapper<FormulaType const> const& formula, boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<std::string> const& rewardModel, bool onlyInitialStatesRelevant, boost::optional<storm::logic::Bound> const& bound, bool qualitative, bool produceSchedulers, std::shared_ptr<ModelCheckerHint> const& hint) : formula(formula), optimizationDirection(optimizationDirection), rewardModel(rewardModel), onlyInitialStatesRelevant(onlyInitialStatesRelevant), bound(bound), qualitative(qualitative), produceSchedulers(produceSchedulers), hint(hint) { // Intentionally left empty. } // The formula that is to be checked. std::reference_wrapper<FormulaType const> formula; // If set, the probabilities will be minimized/maximized. boost::optional<storm::OptimizationDirection> optimizationDirection; // If set, the reward property has to be interpreted over this model. boost::optional<std::string> rewardModel; // If set to true, the model checker may decide to only compute the values for the initial states. bool onlyInitialStatesRelevant; // The bound with which the states will be compared. boost::optional<storm::logic::Bound> bound; // A flag specifying whether the property needs to be checked qualitatively, i.e. compared with bounds 0/1. bool qualitative; // If supported by the model checker and the model formalism, schedulers to achieve a value will be produced // if this flag is set. bool produceSchedulers; // A hint that might contain information that speeds up the modelchecking process (if supported by the model checker) std::shared_ptr<ModelCheckerHint> hint; }; } } #endif /* STORM_MODELCHECKER_CHECKTASK_H_ */