#ifndef STORM_UTILITY_PRISMUTILITY #define STORM_UTILITY_PRISMUTILITY #include "src/storage/LabeledValues.h" #include "src/storage/prism/Program.h" #include "src/exceptions/ExceptionMacros.h" #include "src/exceptions/InvalidArgumentException.h" namespace storm { namespace utility { namespace prism { // A structure holding information about a particular choice. template<typename ValueType, typename KeyType=uint_fast64_t, typename Compare=std::less<uint_fast64_t>> struct Choice { public: Choice(std::string const& actionLabel) : distribution(), actionLabel(actionLabel), choiceLabels() { // Intentionally left empty. } /*! * Returns an iterator to the first element of this choice. * * @return An iterator to the first element of this choice. */ typename std::map<KeyType, ValueType>::iterator begin() { return distribution.begin(); } /*! * Returns an iterator to the first element of this choice. * * @return An iterator to the first element of this choice. */ typename std::map<KeyType, ValueType>::const_iterator begin() const { return distribution.cbegin(); } /*! * Returns an iterator that points past the elements of this choice. * * @return An iterator that points past the elements of this choice. */ typename std::map<KeyType, ValueType>::iterator end() { return distribution.end(); } /*! * Returns an iterator that points past the elements of this choice. * * @return An iterator that points past the elements of this choice. */ typename std::map<KeyType, ValueType>::const_iterator end() const { return distribution.cend(); } /*! * Returns an iterator to the element with the given key, if there is one. Otherwise, the iterator points to * distribution.end(). * * @param value The value to find. * @return An iterator to the element with the given key, if there is one. */ typename std::map<KeyType, ValueType>::iterator find(uint_fast64_t value) { return distribution.find(value); } /*! * Inserts the contents of this object to the given output stream. * * @param out The stream in which to insert the contents. */ friend std::ostream& operator<<(std::ostream& out, Choice<ValueType> const& choice) { out << "<"; for (auto const& stateProbabilityPair : choice.distribution) { out << stateProbabilityPair.first << " : " << stateProbabilityPair.second << ", "; } out << ">"; return out; } /*! * Adds the given label to the labels associated with this choice. * * @param label The label to associate with this choice. */ void addChoiceLabel(uint_fast64_t label) { choiceLabels.insert(label); } /*! * Adds the given label set to the labels associated with this choice. * * @param labelSet The label set to associate with this choice. */ void addChoiceLabels(boost::container::flat_set<uint_fast64_t> const& labelSet) { for (uint_fast64_t label : labelSet) { addChoiceLabel(label); } } /*! * Retrieves the set of labels associated with this choice. * * @return The set of labels associated with this choice. */ boost::container::flat_set<uint_fast64_t> const& getChoiceLabels() const { return choiceLabels; } /*! * Retrieves the action label of this choice. * * @return The action label of this choice. */ std::string const& getActionLabel() const { return actionLabel; } /*! * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, * yet. * * @param state The state for which to add the entry. * @return A reference to the entry that is associated with the given state. */ ValueType& getOrAddEntry(uint_fast64_t state) { auto stateProbabilityPair = distribution.find(state); if (stateProbabilityPair == distribution.end()) { distribution[state] = ValueType(); } return distribution.at(state); } /*! * Retrieves the entry in the choice that is associated with the given state and creates one if none exists, * yet. * * @param state The state for which to add the entry. * @return A reference to the entry that is associated with the given state. */ ValueType const& getOrAddEntry(uint_fast64_t state) const { auto stateProbabilityPair = distribution.find(state); if (stateProbabilityPair == distribution.end()) { distribution[state] = ValueType(); } return distribution.at(state); } private: // The distribution that is associated with the choice. std::map<KeyType, ValueType, Compare> distribution; // The label of the choice. std::string actionLabel; // The labels that are associated with this choice. boost::container::flat_set<uint_fast64_t> choiceLabels; }; /*! * Adds the target state and probability to the given choice and ignores the labels. This function overloads with * other functions to ensure the proper treatment of labels. * * @param choice The choice to which to add the target state and probability. * @param state The target state of the probability. * @param probability The probability to reach the target state in one step. * @param labels A set of labels that is supposed to be associated with this state and probability. NOTE: this * is ignored by this particular function but not by the overloaded functions. */ template<typename ValueType> void addProbabilityToChoice(Choice<ValueType>& choice, uint_fast64_t state, ValueType probability, boost::container::flat_set<uint_fast64_t> const& labels) { choice.getOrAddEntry(state) += probability; } /*! * Adds the target state and probability to the given choice and labels it accordingly. This function overloads * with other functions to ensure the proper treatment of labels. * * @param choice The choice to which to add the target state and probability. * @param state The target state of the probability. * @param probability The probability to reach the target state in one step. * @param labels A set of labels that is supposed to be associated with this state and probability. */ template<typename ValueType> void addProbabilityToChoice(Choice<storm::storage::LabeledValues<ValueType>>& choice, uint_fast64_t state, ValueType probability, boost::container::flat_set<uint_fast64_t> const& labels) { auto& labeledEntry = choice.getOrAddEntry(state); labeledEntry.addValue(probability, labels); } static std::map<std::string, storm::expressions::Expression> parseConstantDefinitionString(storm::prism::Program const& program, std::string const& constantDefinitionString) { std::map<std::string, storm::expressions::Expression> constantDefinitions; std::set<std::string> definedConstants; if (!constantDefinitionString.empty()) { // Parse the string that defines the undefined constants of the model and make sure that it contains exactly // one value for each undefined constant of the model. std::vector<std::string> definitions; boost::split(definitions, constantDefinitionString, boost::is_any_of(",")); for (auto& definition : definitions) { boost::trim(definition); // Check whether the token could be a legal constant definition. uint_fast64_t positionOfAssignmentOperator = definition.find('='); if (positionOfAssignmentOperator == std::string::npos) { throw storm::exceptions::InvalidArgumentException() << "Illegal constant definition string: syntax error."; } // Now extract the variable name and the value from the string. std::string constantName = definition.substr(0, positionOfAssignmentOperator); boost::trim(constantName); std::string value = definition.substr(positionOfAssignmentOperator + 1); boost::trim(value); // Check whether the constant is a legal undefined constant of the program and if so, of what type it is. if (program.hasConstant(constantName)) { // Get the actual constant and check whether it's in fact undefined. auto const& constant = program.getConstant(constantName); LOG_THROW(!constant.isDefined(), storm::exceptions::InvalidArgumentException, "Illegally trying to define already defined constant '" << constantName <<"'."); LOG_THROW(definedConstants.find(constantName) == definedConstants.end(), storm::exceptions::InvalidArgumentException, "Illegally trying to define constant '" << constantName <<"' twice."); definedConstants.insert(constantName); if (constant.getType() == storm::expressions::ExpressionReturnType::Bool) { if (value == "true") { constantDefinitions[constantName] = storm::expressions::Expression::createTrue(); } else if (value == "false") { constantDefinitions[constantName] = storm::expressions::Expression::createFalse(); } else { throw storm::exceptions::InvalidArgumentException() << "Illegal value for boolean constant: " << value << "."; } } else if (constant.getType() == storm::expressions::ExpressionReturnType::Int) { int_fast64_t integerValue = std::stoi(value); constantDefinitions[constantName] = storm::expressions::Expression::createIntegerLiteral(integerValue); } else if (constant.getType() == storm::expressions::ExpressionReturnType::Double) { double doubleValue = std::stod(value); constantDefinitions[constantName] = storm::expressions::Expression::createDoubleLiteral(doubleValue); } } else { throw storm::exceptions::InvalidArgumentException() << "Illegal constant definition string: unknown undefined constant " << constantName << "."; } } } return constantDefinitions; } } // namespace prism } // namespace utility } // namespace storm #endif /* STORM_UTILITY_PRISMUTILITY_H_ */