3 changed files with 444 additions and 280 deletions
			
			
		- 
					478src/storm-pomdp-cli/storm-pomdp.cpp
 - 
					177src/storm-pomdp/analysis/FormulaInformation.cpp
 - 
					69src/storm-pomdp/analysis/FormulaInformation.h
 
@ -0,0 +1,177 @@ | 
				
			|||
#include "storm-pomdp/analysis/FormulaInformation.h"
 | 
				
			|||
#include "storm/logic/Formulas.h"
 | 
				
			|||
#include "storm/logic/FragmentSpecification.h"
 | 
				
			|||
#include "storm/models/sparse/Pomdp.h"
 | 
				
			|||
#include "storm/models/sparse/StandardRewardModel.h"
 | 
				
			|||
#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h"
 | 
				
			|||
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
 | 
				
			|||
 | 
				
			|||
#include "storm/utility/macros.h"
 | 
				
			|||
#include "storm/exceptions/InvalidPropertyException.h"
 | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
    namespace pomdp { | 
				
			|||
        namespace analysis { | 
				
			|||
             | 
				
			|||
            bool FormulaInformation::StateSet::empty() const { | 
				
			|||
                STORM_LOG_ASSERT(states.empty() == observations.empty(), "Inconsistent StateSet."); | 
				
			|||
                return observations.empty(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            FormulaInformation::FormulaInformation() : type(Type::Unsupported) { | 
				
			|||
                // Intentionally left empty
 | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            FormulaInformation::FormulaInformation(Type const& type, storm::solver::OptimizationDirection const& dir, boost::optional<std::string> const& rewardModelName) : type(type), optimizationDirection(dir), rewardModelName(rewardModelName) { | 
				
			|||
                STORM_LOG_ASSERT(!this->rewardModelName.is_initialized() || this->type == Type::NonNestedExpectedRewardFormula, "Got a reward model name for a non-reward formula."); | 
				
			|||
 | 
				
			|||
            } | 
				
			|||
              | 
				
			|||
            FormulaInformation::Type const&  FormulaInformation::getType() const { | 
				
			|||
                return type; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool  FormulaInformation::isNonNestedReachabilityProbability() const { | 
				
			|||
                return type == Type::NonNestedReachabilityProbability; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool  FormulaInformation::isNonNestedExpectedRewardFormula() const { | 
				
			|||
                return type == Type::NonNestedExpectedRewardFormula; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool  FormulaInformation::isUnsupported() const { | 
				
			|||
                return type == Type::Unsupported; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            typename FormulaInformation::StateSet const& FormulaInformation::getTargetStates() const { | 
				
			|||
                STORM_LOG_ASSERT(this->type == Type::NonNestedExpectedRewardFormula || this->type == Type::NonNestedReachabilityProbability, "Target states requested for unexpected formula type."); | 
				
			|||
                return targetStates.get(); | 
				
			|||
            } | 
				
			|||
              | 
				
			|||
            typename FormulaInformation::StateSet const& FormulaInformation::getSinkStates() const { | 
				
			|||
                STORM_LOG_ASSERT(this->type == Type::NonNestedReachabilityProbability, "Sink states requested for unexpected formula type."); | 
				
			|||
               return sinkStates.get(); | 
				
			|||
            } | 
				
			|||
              | 
				
			|||
            std::string const& FormulaInformation::getRewardModelName() const { | 
				
			|||
                STORM_LOG_ASSERT(this->type == Type::NonNestedExpectedRewardFormula, "Reward model requested for unexpected formula type."); | 
				
			|||
                return rewardModelName.get(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            storm::solver::OptimizationDirection const& FormulaInformation::getOptimizationDirection() const { | 
				
			|||
                return optimizationDirection; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool FormulaInformation::minimize() const { | 
				
			|||
                return storm::solver::minimize(optimizationDirection); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            bool FormulaInformation::maximize() const { | 
				
			|||
                return storm::solver::maximize(optimizationDirection); | 
				
			|||
            } | 
				
			|||
           | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            FormulaInformation::StateSet getStateSet(PomdpType const& pomdp, storm::storage::BitVector&& inputStates) { | 
				
			|||
                FormulaInformation::StateSet result; | 
				
			|||
                result.states = std::move(inputStates); | 
				
			|||
                for (auto const& state : result.states) { | 
				
			|||
                    result.observations.insert(pomdp.getObservation(state)); | 
				
			|||
                } | 
				
			|||
                // check if this set is observation-closed, i.e., whether there is a state outside of this set with one of the observations collected above
 | 
				
			|||
                result.observationClosed = true; | 
				
			|||
                for (uint64_t state = result.states.getNextUnsetIndex(0); state < result.states.size(); state = result.states.getNextUnsetIndex(state + 1)) { | 
				
			|||
                    if (result.observations.count(pomdp.getObservation(state)) > 0) { | 
				
			|||
                        result.observationClosed = false; | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                return result; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            void FormulaInformation::updateTargetStates(PomdpType const& pomdp, storm::storage::BitVector&& newTargetStates) { | 
				
			|||
                STORM_LOG_ASSERT(this->type == Type::NonNestedExpectedRewardFormula || this->type == Type::NonNestedReachabilityProbability, "Target states updated for unexpected formula type."); | 
				
			|||
                targetStates = getStateSet(pomdp, std::move(newTargetStates)); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            void FormulaInformation::updateSinkStates(PomdpType const& pomdp, storm::storage::BitVector&& newSinkStates) { | 
				
			|||
                STORM_LOG_ASSERT(this->type == Type::NonNestedReachabilityProbability, "Sink states requested for unexpected formula type."); | 
				
			|||
                sinkStates = getStateSet(pomdp, std::move(newSinkStates)); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            storm::storage::BitVector getStates(storm::logic::Formula const& propositionalFormula, bool formulaInverted, PomdpType const& pomdp) { | 
				
			|||
                storm::modelchecker::SparsePropositionalModelChecker<PomdpType> mc(pomdp); | 
				
			|||
                auto checkResult = mc.check(propositionalFormula); | 
				
			|||
                storm::storage::BitVector resultBitVector(checkResult->asExplicitQualitativeCheckResult().getTruthValuesVector()); | 
				
			|||
                if (formulaInverted) { | 
				
			|||
                    resultBitVector.complement(); | 
				
			|||
                } | 
				
			|||
                return resultBitVector; | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            FormulaInformation getFormulaInformation(PomdpType const& pomdp, storm::logic::ProbabilityOperatorFormula const& formula) { | 
				
			|||
                STORM_LOG_THROW(formula.hasOptimalityType(), storm::exceptions::InvalidPropertyException, "The property does not specify an optimization direction (min/max)"); | 
				
			|||
                STORM_LOG_WARN_COND(!formula.hasBound(), "The probability threshold for the given property will be ignored."); | 
				
			|||
                auto const& subformula = formula.getSubformula(); | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> targetStatesFormula, constraintsStatesFormula; | 
				
			|||
                if (subformula.isEventuallyFormula()) { | 
				
			|||
                    targetStatesFormula = subformula.asEventuallyFormula().getSubformula().asSharedPointer(); | 
				
			|||
                    constraintsStatesFormula = storm::logic::Formula::getTrueFormula()->asSharedPointer(); | 
				
			|||
                } else if (subformula.isUntilFormula()) { | 
				
			|||
                    storm::logic::UntilFormula const &untilFormula = subformula.asUntilFormula(); | 
				
			|||
                    targetStatesFormula = untilFormula.getRightSubformula().asSharedPointer(); | 
				
			|||
                    constraintsStatesFormula = untilFormula.getLeftSubformula().asSharedPointer(); | 
				
			|||
                } | 
				
			|||
                if (targetStatesFormula && targetStatesFormula->isInFragment(storm::logic::propositional()) && constraintsStatesFormula && constraintsStatesFormula->isInFragment(storm::logic::propositional())) { | 
				
			|||
                    FormulaInformation result(FormulaInformation::Type::NonNestedReachabilityProbability, formula.getOptimalityType()); | 
				
			|||
                    result.updateTargetStates(pomdp, getStates(*targetStatesFormula, false, pomdp)); | 
				
			|||
                    result.updateSinkStates(pomdp, getStates(*constraintsStatesFormula, true, pomdp)); | 
				
			|||
                    return result; | 
				
			|||
                } | 
				
			|||
                return FormulaInformation(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            FormulaInformation getFormulaInformation(PomdpType const& pomdp, storm::logic::RewardOperatorFormula const& formula) { | 
				
			|||
                STORM_LOG_THROW(formula.hasOptimalityType(), storm::exceptions::InvalidPropertyException, "The property does not specify an optimization direction (min/max)"); | 
				
			|||
                STORM_LOG_WARN_COND(formula.hasBound(), "The reward threshold for the given property will be ignored."); | 
				
			|||
                std::string rewardModelName = ""; | 
				
			|||
                if (formula.hasRewardModelName()) { | 
				
			|||
                    rewardModelName = formula.getRewardModelName(); | 
				
			|||
                    STORM_LOG_THROW(pomdp.hasRewardModel(rewardModelName), storm::exceptions::InvalidPropertyException, "Selected reward model with name '" << rewardModelName << "' does not exist."); | 
				
			|||
                } else { | 
				
			|||
                    STORM_LOG_THROW(pomdp.hasUniqueRewardModel(), storm::exceptions::InvalidPropertyException, "Reward operator formula does not specify a reward model and the reward model is not unique."); | 
				
			|||
                    rewardModelName = pomdp.getUniqueRewardModelName(); | 
				
			|||
                } | 
				
			|||
                auto const& subformula = formula.getSubformula(); | 
				
			|||
                std::shared_ptr<storm::logic::Formula const> targetStatesFormula; | 
				
			|||
                if (subformula.isEventuallyFormula()) { | 
				
			|||
                    targetStatesFormula = subformula.asEventuallyFormula().getSubformula().asSharedPointer(); | 
				
			|||
                } | 
				
			|||
                if (targetStatesFormula && targetStatesFormula->isInFragment(storm::logic::propositional())) { | 
				
			|||
                    FormulaInformation result(FormulaInformation::Type::NonNestedReachabilityProbability, formula.getOptimalityType(), rewardModelName); | 
				
			|||
                    result.updateTargetStates(pomdp, getStates(*targetStatesFormula, false, pomdp)); | 
				
			|||
                    return result; | 
				
			|||
                } | 
				
			|||
                return FormulaInformation(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            FormulaInformation getFormulaInformation(PomdpType const& pomdp, storm::logic::Formula const& formula) { | 
				
			|||
                if (formula.isProbabilityOperatorFormula()) { | 
				
			|||
                    return getFormulaInformation(pomdp, formula.asProbabilityOperatorFormula()); | 
				
			|||
                } else if (formula.isRewardOperatorFormula()) { | 
				
			|||
                    return getFormulaInformation(pomdp, formula.asRewardOperatorFormula()); | 
				
			|||
                } | 
				
			|||
                return FormulaInformation(); | 
				
			|||
            } | 
				
			|||
             | 
				
			|||
            template FormulaInformation getFormulaInformation<storm::models::sparse::Pomdp<double>>(storm::models::sparse::Pomdp<double> const& pomdp, storm::logic::Formula const& formula); | 
				
			|||
            template FormulaInformation getFormulaInformation<storm::models::sparse::Pomdp<storm::RationalNumber>>(storm::models::sparse::Pomdp<storm::RationalNumber> const& pomdp, storm::logic::Formula const& formula); | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,69 @@ | 
				
			|||
#pragma once | 
				
			|||
 | 
				
			|||
#include <set> | 
				
			|||
#include <string> | 
				
			|||
#include <boost/optional.hpp> | 
				
			|||
 | 
				
			|||
#include "storm/storage/BitVector.h" | 
				
			|||
#include "storm/solver/OptimizationDirection.h" | 
				
			|||
 | 
				
			|||
namespace storm { | 
				
			|||
     | 
				
			|||
    namespace logic { | 
				
			|||
        class Formula; | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    namespace pomdp { | 
				
			|||
        namespace analysis { | 
				
			|||
            class FormulaInformation { | 
				
			|||
            public: | 
				
			|||
                /// Characterizes a certain set of states | 
				
			|||
                struct StateSet { | 
				
			|||
                    storm::storage::BitVector states; // The set of states | 
				
			|||
                    std::set<uint32_t> observations; // The set of the observations that are assigned to at least one state of the set | 
				
			|||
                    bool observationClosed; // True iff this state set can be uniquely characterized by the observations | 
				
			|||
                    bool empty() const; | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
                /// Possible supported formula types | 
				
			|||
                enum class Type { | 
				
			|||
                    NonNestedReachabilityProbability, // e.g. 'Pmax=? [F "target"]' or 'Pmin=? [!"sink" U "target"]' | 
				
			|||
                    NonNestedExpectedRewardFormula, // e.g. 'Rmin=? [F x>0 ]' | 
				
			|||
                    Unsupported // The formula type is unsupported | 
				
			|||
                }; | 
				
			|||
                 | 
				
			|||
                FormulaInformation(); // Unsupported | 
				
			|||
                FormulaInformation(Type const& type, storm::solver::OptimizationDirection const& dir, boost::optional<std::string> const& rewardModelName = boost::none); | 
				
			|||
                 | 
				
			|||
                Type const& getType() const; | 
				
			|||
                bool isNonNestedReachabilityProbability() const; | 
				
			|||
                bool isNonNestedExpectedRewardFormula() const; | 
				
			|||
                bool isUnsupported() const; | 
				
			|||
                StateSet const& getTargetStates() const; | 
				
			|||
                StateSet const& getSinkStates() const; // Shall not be called for reward formulas | 
				
			|||
                std::string const& getRewardModelName() const; // Shall not be called for probability formulas | 
				
			|||
                storm::solver::OptimizationDirection const& getOptimizationDirection() const; | 
				
			|||
                bool minimize() const; | 
				
			|||
                bool maximize() const; | 
				
			|||
                 | 
				
			|||
                template <typename PomdpType> | 
				
			|||
                void updateTargetStates(PomdpType const& pomdp, storm::storage::BitVector&& newTargetStates); | 
				
			|||
                 | 
				
			|||
                template <typename PomdpType> | 
				
			|||
                void updateSinkStates(PomdpType const& pomdp, storm::storage::BitVector&& newSinkStates); | 
				
			|||
                 | 
				
			|||
            private: | 
				
			|||
                Type type; | 
				
			|||
                storm::solver::OptimizationDirection optimizationDirection; | 
				
			|||
                boost::optional<StateSet> targetStates; | 
				
			|||
                boost::optional<StateSet> sinkStates; | 
				
			|||
                boost::optional<std::string> rewardModelName; | 
				
			|||
            }; | 
				
			|||
             | 
				
			|||
            template <typename PomdpType> | 
				
			|||
            FormulaInformation getFormulaInformation(PomdpType const& pomdp, storm::logic::Formula const& formula); | 
				
			|||
 | 
				
			|||
             | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue