diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp new file mode 100644 index 000000000..c9744d90c --- /dev/null +++ b/src/builder/DdJaniModelBuilder.cpp @@ -0,0 +1,125 @@ +#include "src/builder/DdJaniModelBuilder.h" + +#include <sstream> + +#include <boost/algorithm/string/join.hpp> + +#include "src/logic/Formulas.h" + +#include "src/utility/macros.h" +#include "src/utility/jani.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace builder { + + template <storm::dd::DdType Type, typename ValueType> + DdJaniModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(true), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() { + // Intentionally left empty. + } + + template <storm::dd::DdType Type, typename ValueType> + DdJaniModelBuilder<Type, ValueType>::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() { + this->preserveFormula(formula); + this->setTerminalStatesFromFormula(formula); + } + + template <storm::dd::DdType Type, typename ValueType> + DdJaniModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() { + if (formulas.empty()) { + this->buildAllRewardModels = true; + } else { + for (auto const& formula : formulas) { + this->preserveFormula(*formula); + } + if (formulas.size() == 1) { + this->setTerminalStatesFromFormula(*formulas.front()); + } + } + } + + template <storm::dd::DdType Type, typename ValueType> + void DdJaniModelBuilder<Type, ValueType>::Options::preserveFormula(storm::logic::Formula const& formula) { + // If we already had terminal states, we need to erase them. + if (terminalStates) { + terminalStates.reset(); + } + if (negatedTerminalStates) { + negatedTerminalStates.reset(); + } + + // If we are not required to build all reward models, we determine the reward models we need to build. + if (!buildAllRewardModels) { + std::set<std::string> referencedRewardModels = formula.getReferencedRewardModels(); + rewardModelsToBuild.insert(referencedRewardModels.begin(), referencedRewardModels.end()); + } + } + + template <storm::dd::DdType Type, typename ValueType> + void DdJaniModelBuilder<Type, ValueType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { + if (formula.isAtomicExpressionFormula()) { + terminalStates = formula.asAtomicExpressionFormula().getExpression(); + } else if (formula.isEventuallyFormula()) { + storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula(); + if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) { + this->setTerminalStatesFromFormula(sub); + } + } else if (formula.isUntilFormula()) { + storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula(); + if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) { + this->setTerminalStatesFromFormula(right); + } + storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula(); + if (left.isAtomicExpressionFormula()) { + negatedTerminalStates = left.asAtomicExpressionFormula().getExpression(); + } + } else if (formula.isProbabilityOperatorFormula()) { + storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula(); + if (sub.isEventuallyFormula() || sub.isUntilFormula()) { + this->setTerminalStatesFromFormula(sub); + } + } + } + + template <storm::dd::DdType Type, typename ValueType> + void DdJaniModelBuilder<Type, ValueType>::Options::addConstantDefinitionsFromString(storm::jani::Model const& model, std::string const& constantDefinitionString) { + std::map<storm::expressions::Variable, storm::expressions::Expression> newConstantDefinitions = storm::utility::jani::parseConstantDefinitionString(model, constantDefinitionString); + + // If there is at least one constant that is defined, and the constant definition map does not yet exist, + // we need to create it. + if (!constantDefinitions && !newConstantDefinitions.empty()) { + constantDefinitions = std::map<storm::expressions::Variable, storm::expressions::Expression>(); + } + + // Now insert all the entries that need to be defined. + for (auto const& entry : newConstantDefinitions) { + constantDefinitions.get().insert(entry); + } + } + + template <storm::dd::DdType Type, typename ValueType> + DdJaniModelBuilder<Type, ValueType>::DdJaniModelBuilder(storm::jani::Model const& model, Options const& options) : options(options) { + if (options.constantDefinitions) { + this->model = model.defineUndefinedConstants(options.constantDefinitions.get()); + } else { + this->model = model; + } + + if (this->model->hasUndefinedConstants()) { + std::vector<std::reference_wrapper<storm::jani::Constant const>> undefinedConstants = this->model->getUndefinedConstants(); + std::vector<std::string> strings; + for (auto const& constant : undefinedConstants) { + std::stringstream stream; + stream << constant.get().getName() << " (" << constant.get().getType() << ")"; + strings.push_back(stream.str()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " << boost::join(strings, ", ") << "."); + } + + this->model = this->model->substituteConstants(); + } + + template class DdJaniModelBuilder<storm::dd::DdType::CUDD, double>; + template class DdJaniModelBuilder<storm::dd::DdType::Sylvan, double>; + } +} \ No newline at end of file diff --git a/src/builder/DdJaniModelBuilder.h b/src/builder/DdJaniModelBuilder.h new file mode 100644 index 000000000..983b7cd99 --- /dev/null +++ b/src/builder/DdJaniModelBuilder.h @@ -0,0 +1,121 @@ +#pragma once + +#include <boost/optional.hpp> + +#include "src/storage/dd/DdType.h" + +#include "src/logic/Formula.h" + +#include "src/storage/jani/Model.h" + +namespace storm { + namespace models { + namespace symbolic { + template <storm::dd::DdType Type, typename ValueType> + class Model; + } + } + + namespace builder { + + template <storm::dd::DdType Type, typename ValueType = double> + class DdJaniModelBuilder { + public: + struct Options { + /*! + * Creates an object representing the default building options. + */ + Options(); + + /*! Creates an object representing the suggested building options assuming that the given formula is the + * only one to check. Additional formulas may be preserved by calling <code>preserveFormula</code>. + * + * @param formula The formula based on which to choose the building options. + */ + Options(storm::logic::Formula const& formula); + + /*! Creates an object representing the suggested building options assuming that the given formulas are + * the only ones to check. Additional formulas may be preserved by calling <code>preserveFormula</code>. + * + * @param formula Thes formula based on which to choose the building options. + */ + Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas); + + /*! + * Sets the constants definitions from the given string. The string must be of the form 'X=a,Y=b,Z=c', + * etc. where X,Y,Z are the variable names and a,b,c are the values of the constants. + * + * @param program The program managing the constants that shall be defined. Note that the program itself + * is not modified whatsoever. + * @param constantDefinitionString The string from which to parse the constants' values. + */ + void addConstantDefinitionsFromString(storm::jani::Model const& model, std::string const& constantDefinitionString); + + /*! + * Changes the options in a way that ensures that the given formula can be checked on the model once it + * has been built. + * + * @param formula The formula that is to be ''preserved''. + */ + void preserveFormula(storm::logic::Formula const& formula); + + /*! + * Analyzes the given formula and sets an expression for the states states of the model that can be + * treated as terminal states. Note that this may interfere with checking properties different than the + * one provided. + * + * @param formula The formula used to (possibly) derive an expression for the terminal states of the + * model. + */ + void setTerminalStatesFromFormula(storm::logic::Formula const& formula); + + // A flag that indicates whether or not all reward models are to be build. + bool buildAllRewardModels; + + // A list of reward models to be build in case not all reward models are to be build. + std::set<std::string> rewardModelsToBuild; + + // An optional mapping that, if given, contains defining expressions for undefined constants. + boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> constantDefinitions; + + // An optional expression or label that (a subset of) characterizes the terminal states of the model. + // If this is set, the outgoing transitions of these states are replaced with a self-loop. + boost::optional<storm::expressions::Expression> terminalStates; + + // An optional expression or label whose negation characterizes (a subset of) the terminal states of the + // model. If this is set, the outgoing transitions of these states are replaced with a self-loop. + boost::optional<storm::expressions::Expression> negatedTerminalStates; + }; + + /*! + * Creates a builder for the given model that uses the given options. + */ + DdJaniModelBuilder(storm::jani::Model const& model, Options const& options = Options()); + + /*! + * Translates the given program into a symbolic model (i.e. one that stores the transition relation as a + * decision diagram). + * + * @param model The model to translate. + * @return A pointer to the resulting model. + */ + std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> translate(); + + /*! + * Retrieves the model that was actually translated (i.e. including constant substitutions etc.). Note + * that this function may only be called after a succesful translation. + * + * @return The translated model. + */ + storm::jani::Model const& getTranslatedModel() const; + + private: + /// The model to translate. + boost::optional<storm::jani::Model> model; + + /// The options to use for building the model. + Options options; + }; + + } +} \ No newline at end of file diff --git a/src/storage/jani/Assignment.cpp b/src/storage/jani/Assignment.cpp index a73c40d93..cea88f23e 100644 --- a/src/storage/jani/Assignment.cpp +++ b/src/storage/jani/Assignment.cpp @@ -15,6 +15,10 @@ namespace storm { return expression; } + void Assignment::setAssignedExpression(storm::expressions::Expression const& expression) { + this->expression = expression; + } + std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) { stream << assignment.getExpressionVariable().getName() << " := " << assignment.getAssignedExpression(); return stream; diff --git a/src/storage/jani/Assignment.h b/src/storage/jani/Assignment.h index 4fc0a5330..58c078d20 100644 --- a/src/storage/jani/Assignment.h +++ b/src/storage/jani/Assignment.h @@ -22,6 +22,11 @@ namespace storm { * Retrieves the expression whose value is assigned to the target variable. */ storm::expressions::Expression const& getAssignedExpression() const; + + /*! + * Sets a new expression that is assigned to the target variable. + */ + void setAssignedExpression(storm::expressions::Expression const& expression); friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment); diff --git a/src/storage/jani/Automaton.cpp b/src/storage/jani/Automaton.cpp index f76d0fc38..79f658356 100644 --- a/src/storage/jani/Automaton.cpp +++ b/src/storage/jani/Automaton.cpp @@ -7,6 +7,132 @@ namespace storm { namespace jani { + namespace detail { + EdgeIterator::EdgeIterator(Automaton& automaton, outer_iter out_it, outer_iter out_ite, inner_iter in_it) : automaton(automaton), out_it(out_it), out_ite(out_ite), in_it(in_it) { + // Intentionally left empty. + } + + EdgeIterator& EdgeIterator::operator++() { + incrementIterator(); + return *this; + } + + EdgeIterator& EdgeIterator::operator++(int) { + incrementIterator(); + return *this; + } + + Edge& EdgeIterator::operator*() { + return *in_it; + } + + bool EdgeIterator::operator==(EdgeIterator const& other) const { + return this->out_it == other.out_it && this->in_it == other.in_it; + } + + bool EdgeIterator::operator!=(EdgeIterator const& other) const { + return !(*this == other); + } + + void EdgeIterator::incrementIterator() { + ++in_it; + + // If the inner iterator has reached its end move it to the beginning of the next outer element. + if (in_it == out_it->end()) { + ++out_it; + while (out_it != out_ite && out_it->empty()) { + ++out_it; + in_it = out_it->end(); + } + if (out_it != out_ite) { + in_it = out_it->begin(); + } + } + } + + ConstEdgeIterator::ConstEdgeIterator(Automaton const& automaton, outer_iter out_it, outer_iter out_ite, inner_iter in_it) : automaton(automaton), out_it(out_it), out_ite(out_ite), in_it(in_it) { + // Intentionally left empty. + } + + ConstEdgeIterator& ConstEdgeIterator::operator++() { + incrementIterator(); + return *this; + } + + ConstEdgeIterator& ConstEdgeIterator::operator++(int) { + incrementIterator(); + return *this; + } + + Edge const& ConstEdgeIterator::operator*() const { + return *in_it; + } + + bool ConstEdgeIterator::operator==(ConstEdgeIterator const& other) const { + return this->out_it == other.out_it && this->in_it == other.in_it; + } + + bool ConstEdgeIterator::operator!=(ConstEdgeIterator const& other) const { + return !(*this == other); + } + + void ConstEdgeIterator::incrementIterator() { + ++in_it; + + // If the inner iterator has reached its end move it to the beginning of the next outer element. + if (in_it == out_it->end()) { + ++out_it; + while (out_it != out_ite && out_it->empty()) { + ++out_it; + in_it = out_it->end(); + } + if (out_it != out_ite) { + in_it = out_it->begin(); + } + } + } + + Edges::Edges(Automaton& automaton) : automaton(automaton) { + // Intentionally left empty. + } + + EdgeIterator Edges::begin() { + auto outer = automaton.edges.begin(); + while (outer != automaton.edges.end() && outer->empty()) { + ++outer; + } + if (outer == automaton.edges.end()) { + return end(); + } else { + return EdgeIterator(automaton, outer, automaton.edges.end(), outer->begin()); + } + } + + EdgeIterator Edges::end() { + return EdgeIterator(automaton, automaton.edges.end(), automaton.edges.end(), automaton.edges.back().end()); + } + + ConstEdges::ConstEdges(Automaton const& automaton) : automaton(automaton) { + // Intentionally left empty. + } + + ConstEdgeIterator ConstEdges::begin() const { + auto outer = automaton.edges.begin(); + while (outer != automaton.edges.end() && outer->empty()) { + ++outer; + } + if (outer == automaton.edges.end()) { + return end(); + } else { + return ConstEdgeIterator(automaton, outer, automaton.edges.end(), outer->begin()); + } + } + + ConstEdgeIterator ConstEdges::end() const { + return ConstEdgeIterator(automaton, automaton.edges.end(), automaton.edges.end(), automaton.edges.back().end()); + } + } + Automaton::Automaton(std::string const& name) : name(name) { // Intentionally left empty. } @@ -26,7 +152,11 @@ namespace storm { void Automaton::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { variables.addUnboundedIntegerVariable(variable); } - + + VariableSet& Automaton::getVariables() { + return variables; + } + VariableSet const& Automaton::getVariables() const { return variables; } @@ -90,6 +220,14 @@ namespace storm { edges[edge.getSourceLocationId()].addEdge(edge); } + Automaton::Edges Automaton::getEdges() { + return Edges(*this); + } + + Automaton::ConstEdges Automaton::getEdges() const { + return ConstEdges(*this); + } + uint64_t Automaton::getNumberOfLocations() const { return edges.size(); } diff --git a/src/storage/jani/Automaton.h b/src/storage/jani/Automaton.h index 81e231f16..36a525703 100644 --- a/src/storage/jani/Automaton.h +++ b/src/storage/jani/Automaton.h @@ -11,8 +11,122 @@ namespace storm { namespace jani { + class Automaton; + + namespace detail { + class EdgeIterator { + private: + typedef std::vector<EdgeSet>::iterator outer_iter; + typedef EdgeSet::iterator inner_iter; + + public: + /*! + * Creates an iterator over all edges. + */ + EdgeIterator(Automaton& automaton, outer_iter out_it, outer_iter out_ite, inner_iter in_it); + + // Methods to advance the iterator. + EdgeIterator& operator++(); + EdgeIterator& operator++(int); + + Edge& operator*(); + + bool operator==(EdgeIterator const& other) const; + bool operator!=(EdgeIterator const& other) const; + + private: + // Moves the iterator to the next position. + void incrementIterator(); + + // The underlying automaton. + Automaton& automaton; + + // The current iterator positions. + outer_iter out_it; + outer_iter out_ite; + inner_iter in_it; + }; + + class ConstEdgeIterator { + private: + typedef std::vector<EdgeSet>::const_iterator outer_iter; + typedef EdgeSet::const_iterator inner_iter; + + public: + /*! + * Creates an iterator over all edges. + */ + ConstEdgeIterator(Automaton const& automaton, outer_iter out_it, outer_iter out_ite, inner_iter in_it); + + // Methods to advance the iterator. + ConstEdgeIterator& operator++(); + ConstEdgeIterator& operator++(int); + + Edge const& operator*() const; + + bool operator==(ConstEdgeIterator const& other) const; + bool operator!=(ConstEdgeIterator const& other) const; + + private: + // Moves the iterator to the next position. + void incrementIterator(); + + // The underlying automaton. + Automaton const& automaton; + + // The current iterator positions. + outer_iter out_it; + outer_iter out_ite; + inner_iter in_it; + }; + + class Edges { + public: + Edges(Automaton& automaton); + + /*! + * Retrieves an iterator to all edges of the automaton. + */ + EdgeIterator begin(); + + /*! + * Retrieves the end iterator to edges of the automaton. + */ + EdgeIterator end(); + + private: + // The underlying automaton. + Automaton& automaton; + }; + + class ConstEdges { + public: + ConstEdges(Automaton const& automaton); + + /*! + * Retrieves an iterator to all edges of the automaton. + */ + ConstEdgeIterator begin() const; + + /*! + * Retrieves the end iterator to edges of the automaton. + */ + ConstEdgeIterator end() const; + + private: + // The underlying automaton. + Automaton const& automaton; + }; + } + class Automaton { public: + friend class detail::Edges; + friend class detail::ConstEdges; + + typedef detail::Edges Edges; + typedef detail::ConstEdges ConstEdges; + /*! * Creates an empty automaton. */ @@ -37,7 +151,12 @@ namespace storm { * Adds the given unbounded integer variable to this automaton. */ void addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable); - + + /*! + * Retrieves the variables of this automaton. + */ + VariableSet& getVariables(); + /*! * Retrieves the variables of this automaton. */ @@ -106,6 +225,16 @@ namespace storm { */ void addEdge(Edge const& edge); + /*! + * Retrieves the edges of the automaton. + */ + Edges getEdges(); + + /*! + * Retrieves the edges of the automaton. + */ + ConstEdges getEdges() const; + /*! * Retrieves the number of locations. */ diff --git a/src/storage/jani/BoundedIntegerVariable.cpp b/src/storage/jani/BoundedIntegerVariable.cpp index 879f9a165..4ab7e5717 100644 --- a/src/storage/jani/BoundedIntegerVariable.cpp +++ b/src/storage/jani/BoundedIntegerVariable.cpp @@ -11,9 +11,17 @@ namespace storm { return lowerBound; } + void BoundedIntegerVariable::setLowerBound(storm::expressions::Expression const& expression) { + this->lowerBound = expression; + } + storm::expressions::Expression const& BoundedIntegerVariable::getUpperBound() const { return upperBound; } + void BoundedIntegerVariable::setUpperBound(storm::expressions::Expression const& expression) { + this->upperBound = expression; + } + } } \ No newline at end of file diff --git a/src/storage/jani/BoundedIntegerVariable.h b/src/storage/jani/BoundedIntegerVariable.h index b686f4a0e..5e62c855a 100644 --- a/src/storage/jani/BoundedIntegerVariable.h +++ b/src/storage/jani/BoundedIntegerVariable.h @@ -18,11 +18,21 @@ namespace storm { */ storm::expressions::Expression const& getLowerBound() const; + /*! + * Sets a new lower bound of the variable. + */ + void setLowerBound(storm::expressions::Expression const& expression); + /*! * Retrieves the expression defining the upper bound of the variable. */ storm::expressions::Expression const& getUpperBound() const; + /*! + * Sets a new upper bound of the variable. + */ + void setUpperBound(storm::expressions::Expression const& expression); + private: // The expression defining the lower bound of the variable. storm::expressions::Expression lowerBound; diff --git a/src/storage/jani/Constant.cpp b/src/storage/jani/Constant.cpp index a85331d40..94aa4d522 100644 --- a/src/storage/jani/Constant.cpp +++ b/src/storage/jani/Constant.cpp @@ -35,5 +35,13 @@ namespace storm { return getType().isRationalType(); } + storm::expressions::Variable const& Constant::getExpressionVariable() const { + return variable; + } + + storm::expressions::Expression const& Constant::getExpression() const { + return expression.get(); + } + } } diff --git a/src/storage/jani/Constant.h b/src/storage/jani/Constant.h index 1cfed043d..eb14f44ca 100644 --- a/src/storage/jani/Constant.h +++ b/src/storage/jani/Constant.h @@ -52,6 +52,16 @@ namespace storm { */ bool isRealConstant() const; + /*! + * Retrieves the expression variable associated with this constant. + */ + storm::expressions::Variable const& getExpressionVariable() const; + + /*! + * Retrieves the expression that defines this constant (if any). + */ + storm::expressions::Expression const& getExpression() const; + private: // The name of the constant. std::string name; diff --git a/src/storage/jani/Edge.cpp b/src/storage/jani/Edge.cpp index 5b8003815..8176952a8 100644 --- a/src/storage/jani/Edge.cpp +++ b/src/storage/jani/Edge.cpp @@ -23,14 +23,26 @@ namespace storm { return rate.get(); } + void Edge::setRate(storm::expressions::Expression const& rate) { + this->rate = rate; + } + storm::expressions::Expression const& Edge::getGuard() const { return guard; } + void Edge::setGuard(storm::expressions::Expression const& guard) { + this->guard = guard; + } + std::vector<EdgeDestination> const& Edge::getDestinations() const { return destinations; } + std::vector<EdgeDestination>& Edge::getDestinations() { + return destinations; + } + void Edge::addDestination(EdgeDestination const& destination) { destinations.push_back(destination); } diff --git a/src/storage/jani/Edge.h b/src/storage/jani/Edge.h index ff5def7ee..1571bf9c1 100644 --- a/src/storage/jani/Edge.h +++ b/src/storage/jani/Edge.h @@ -30,16 +30,31 @@ namespace storm { * Retrieves the rate of this edge. Note that calling this is only valid if the edge has an associated rate. */ storm::expressions::Expression const& getRate() const; + + /*! + * Sets a new rate for this edge. + */ + void setRate(storm::expressions::Expression const& rate); /*! * Retrieves the guard of this edge. */ storm::expressions::Expression const& getGuard() const; + /*! + * Sets a new guard for this edge. + */ + void setGuard(storm::expressions::Expression const& guard); + /*! * Retrieves the destinations of this edge. */ std::vector<EdgeDestination> const& getDestinations() const; + + /*! + * Retrieves the destinations of this edge. + */ + std::vector<EdgeDestination>& getDestinations(); /*! * Adds the given destination to the destinations of this edge. diff --git a/src/storage/jani/EdgeDestination.cpp b/src/storage/jani/EdgeDestination.cpp index 35554545d..bee1e0a3a 100644 --- a/src/storage/jani/EdgeDestination.cpp +++ b/src/storage/jani/EdgeDestination.cpp @@ -30,6 +30,14 @@ namespace storm { return probability; } + void EdgeDestination::setProbability(storm::expressions::Expression const& probability) { + this->probability = probability; + } + + std::vector<Assignment>& EdgeDestination::getAssignments() { + return assignments; + } + std::vector<Assignment> const& EdgeDestination::getAssignments() const { return assignments; } diff --git a/src/storage/jani/EdgeDestination.h b/src/storage/jani/EdgeDestination.h index 07efeece1..c967518eb 100644 --- a/src/storage/jani/EdgeDestination.h +++ b/src/storage/jani/EdgeDestination.h @@ -37,6 +37,16 @@ namespace storm { */ storm::expressions::Expression const& getProbability() const; + /*! + * Sets a new probability for this edge destination. + */ + void setProbability(storm::expressions::Expression const& probability); + + /*! + * Retrieves the assignments to make when choosing this destination. + */ + std::vector<Assignment>& getAssignments(); + /*! * Retrieves the assignments to make when choosing this destination. */ diff --git a/src/storage/jani/EdgeSet.cpp b/src/storage/jani/EdgeSet.cpp index 25704a864..d71b3f5be 100644 --- a/src/storage/jani/EdgeSet.cpp +++ b/src/storage/jani/EdgeSet.cpp @@ -27,5 +27,9 @@ namespace storm { edges.push_back(edge); } + bool EdgeSet::empty() const { + return edges.empty(); + } + } } \ No newline at end of file diff --git a/src/storage/jani/EdgeSet.h b/src/storage/jani/EdgeSet.h index e9fe03fbf..a9e7336ad 100644 --- a/src/storage/jani/EdgeSet.h +++ b/src/storage/jani/EdgeSet.h @@ -21,6 +21,11 @@ namespace storm { */ void addEdge(Edge const& edge); + /*! + * Retrieves whether the set of edges is empty. + */ + bool empty() const; + // Methods to get an iterator to the edges. iterator begin(); iterator end(); diff --git a/src/storage/jani/Exporter.cpp b/src/storage/jani/Exporter.cpp index e5561b9b6..643099b78 100644 --- a/src/storage/jani/Exporter.cpp +++ b/src/storage/jani/Exporter.cpp @@ -227,7 +227,7 @@ namespace storm { appendIndent(out, indent + 1); appendField(out, "ref"); - storm::jani::Variable const& variable = model.getVariables().hasVariable(assignment.getExpressionVariable()) ? model.getVariables().getVariable(assignment.getExpressionVariable()) : automaton.getVariables().getVariable(assignment.getExpressionVariable()); + storm::jani::Variable const& variable = model.getGlobalVariables().hasVariable(assignment.getExpressionVariable()) ? model.getGlobalVariables().getVariable(assignment.getExpressionVariable()) : automaton.getVariables().getVariable(assignment.getExpressionVariable()); appendValue(out, variable.getName()); out << ","; clearLine(out); @@ -399,7 +399,7 @@ namespace storm { clearLine(out); appendActions(out, model, 1); clearLine(out); - appendVariables(out, model.getVariables(), 1); + appendVariables(out, model.getGlobalVariables(), 1); clearLine(out); appendAutomata(out, model, 1); clearLine(out); diff --git a/src/storage/jani/Model.cpp b/src/storage/jani/Model.cpp index 87149f611..5ef53fe88 100644 --- a/src/storage/jani/Model.cpp +++ b/src/storage/jani/Model.cpp @@ -8,6 +8,7 @@ #include "src/utility/macros.h" #include "src/exceptions/WrongFormatException.h" +#include "src/exceptions/InvalidOperationException.h" namespace storm { namespace jani { @@ -72,6 +73,24 @@ namespace storm { return constants.size() - 1; } + bool Model::hasConstant(std::string const& name) const { + return constantToIndex.find(name) != constantToIndex.end(); + } + + Constant const& Model::getConstant(std::string const& name) const { + auto it = constantToIndex.find(name); + STORM_LOG_THROW(it != constantToIndex.end(), storm::exceptions::WrongFormatException, "Unable to retrieve unknown constant '" << name << "'."); + return constants[it->second]; + } + + std::vector<Constant> const& Model::getConstants() const { + return constants; + } + + std::vector<Constant>& Model::getConstants() { + return constants; + } + void Model::addBooleanVariable(BooleanVariable const& variable) { globalVariables.addBooleanVariable(variable); } @@ -83,8 +102,12 @@ namespace storm { void Model::addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable) { globalVariables.addUnboundedIntegerVariable(variable); } - - VariableSet const& Model::getVariables() const { + + VariableSet& Model::getGlobalVariables() { + return globalVariables; + } + + VariableSet const& Model::getGlobalVariables() const { return globalVariables; } @@ -104,6 +127,14 @@ namespace storm { return automata.size() - 1; } + std::vector<Automaton>& Model::getAutomata() { + return automata; + } + + std::vector<Automaton> const& Model::getAutomata() const { + return automata; + } + std::shared_ptr<Composition> Model::getStandardSystemComposition() const { std::set<std::string> fullSynchronizationAlphabet = getActionNames(false); @@ -129,6 +160,109 @@ namespace storm { return result; } + Model Model::defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const { + Model result(*this); + + std::set<storm::expressions::Variable> definedUndefinedConstants; + for (auto& constant : result.constants) { + // If the constant is already defined, we need to replace the appearances of undefined constants in its + // defining expression + if (constant.isDefined()) { + // Make sure we are not trying to define an already defined constant. + STORM_LOG_THROW(constantDefinitions.find(constant.getExpressionVariable()) == constantDefinitions.end(), storm::exceptions::InvalidOperationException, "Illegally defining already defined constant '" << constant.getName() << "'."); + } else { + auto const& variableExpressionPair = constantDefinitions.find(constant.getExpressionVariable()); + + if (variableExpressionPair != constantDefinitions.end()) { + // If we need to define it, we add it to the defined constants and assign it the appropriate expression. + definedUndefinedConstants.insert(constant.getExpressionVariable()); + + // Make sure the type of the constant is correct. + STORM_LOG_THROW(variableExpressionPair->second.getType() == constant.getType(), storm::exceptions::InvalidOperationException, "Illegal type of expression defining constant '" << constant.getName() << "'."); + + // Now define the constant. + constant.define(variableExpressionPair->second); + } + } + } + + // As a sanity check, we make sure that the given mapping does not contain any definitions for identifiers + // that are not undefined constants. + for (auto const& constantExpressionPair : constantDefinitions) { + STORM_LOG_THROW(definedUndefinedConstants.find(constantExpressionPair.first) != definedUndefinedConstants.end(), storm::exceptions::InvalidOperationException, "Unable to define non-existant constant '" << constantExpressionPair.first.getName() << "'."); + } + return result; + } + + bool Model::hasUndefinedConstants() const { + for (auto const& constant : constants) { + if (!constant.isDefined()) { + return true; + } + } + return false; + } + + std::vector<std::reference_wrapper<Constant const>> Model::getUndefinedConstants() const { + std::vector<std::reference_wrapper<Constant const>> result; + + for (auto const& constant : constants) { + if (!constant.isDefined()) { + result.push_back(constant); + } + } + + return result; + } + + Model Model::substituteConstants() const { + Model result(*this); + + // Gather all defining expressions of constants. + std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution; + for (auto& constant : result.getConstants()) { + if (constant.isDefined()) { + constant.define(constant.getExpression().substitute(constantSubstitution)); + constantSubstitution[constant.getExpressionVariable()] = constant.getExpression(); + } + } + + // Substitute constants in all global variables. + for (auto& variable : result.getGlobalVariables()) { + variable.setInitialValue(variable.getInitialValue().substitute(constantSubstitution)); + } + for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { + variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution)); + variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution)); + } + + // Substitute constants in variables of automata and their edges. + for (auto& automaton : result.getAutomata()) { + for (auto& variable : automaton.getVariables()) { + variable.setInitialValue(variable.getInitialValue().substitute(constantSubstitution)); + } + for (auto& variable : automaton.getVariables().getBoundedIntegerVariables()) { + variable.setLowerBound(variable.getLowerBound().substitute(constantSubstitution)); + variable.setUpperBound(variable.getUpperBound().substitute(constantSubstitution)); + } + + for (auto& edge : automaton.getEdges()) { + edge.setGuard(edge.getGuard().substitute(constantSubstitution)); + if (edge.hasRate()) { + edge.setRate(edge.getRate().substitute(constantSubstitution)); + } + for (auto& destination : edge.getDestinations()) { + destination.setProbability(destination.getProbability().substitute(constantSubstitution)); + for (auto& assignment : destination.getAssignments()) { + assignment.setAssignedExpression(assignment.getAssignedExpression().substitute(constantSubstitution)); + } + } + } + } + + return result; + } + bool Model::checkValidity(bool logdbg) const { // TODO switch to exception based return value. diff --git a/src/storage/jani/Model.h b/src/storage/jani/Model.h index a01571707..b1e5e3f9a 100644 --- a/src/storage/jani/Model.h +++ b/src/storage/jani/Model.h @@ -77,6 +77,26 @@ namespace storm { */ uint64_t addConstant(Constant const& constant); + /*! + * Retrieves whether the model has a constant with the given name. + */ + bool hasConstant(std::string const& name) const; + + /*! + * Retrieves the constants of the model. + */ + std::vector<Constant> const& getConstants() const; + + /*! + * Retrieves the constants of the model. + */ + std::vector<Constant>& getConstants(); + + /*! + * Retrieves the constant with the given name (if any). + */ + Constant const& getConstant(std::string const& name) const; + /*! * Adds the given boolean variable to this model. */ @@ -91,11 +111,16 @@ namespace storm { * Adds the given unbounded integer variable to this model. */ void addUnboundedIntegerVariable(UnboundedIntegerVariable const& variable); - + + /*! + * Retrieves the variables of this automaton. + */ + VariableSet& getGlobalVariables(); + /*! * Retrieves the variables of this automaton. */ - VariableSet const& getVariables() const; + VariableSet const& getGlobalVariables() const; /*! * Retrieves the manager responsible for the expressions in the JANI model. @@ -112,6 +137,16 @@ namespace storm { */ uint64_t addAutomaton(Automaton const& automaton); + /*! + * Retrieves the automata of the model. + */ + std::vector<Automaton>& getAutomata(); + + /*! + * Retrieves the automata of the model. + */ + std::vector<Automaton> const& getAutomata() const; + /*! * Sets the system composition expression of the JANI model. */ @@ -137,6 +172,28 @@ namespace storm { */ std::string const& getSilentActionName() const; + /*! + * Defines the undefined constants of the model by the given expressions. The original model is not modified, + * but instead a new model is created. + */ + Model defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const; + + /*! + * Retrieves whether the model still has undefined constants. + */ + bool hasUndefinedConstants() const; + + /*! + * Retrieves all undefined constants of the model. + */ + std::vector<std::reference_wrapper<Constant const>> getUndefinedConstants() const; + + /*! + * Substitutes all constants in all expressions of the model. The original model is not modified, but + * instead a new model is created. + */ + Model substituteConstants() const; + /*! * Checks if the model is valid JANI, which should be verified before any further operations are applied to a model. */ diff --git a/src/storage/jani/Variable.cpp b/src/storage/jani/Variable.cpp index 9601d7684..84f927802 100644 --- a/src/storage/jani/Variable.cpp +++ b/src/storage/jani/Variable.cpp @@ -25,5 +25,9 @@ namespace storm { return initialValue; } + void Variable::setInitialValue(storm::expressions::Expression const& initialValue) { + this->initialValue = initialValue; + } + } } \ No newline at end of file diff --git a/src/storage/jani/Variable.h b/src/storage/jani/Variable.h index b0cbf5d5a..c77e21e93 100644 --- a/src/storage/jani/Variable.h +++ b/src/storage/jani/Variable.h @@ -31,6 +31,11 @@ namespace storm { */ storm::expressions::Expression const& getInitialValue() const; + /*! + * Sets a new value as the initial value of the variable. + */ + void setInitialValue(storm::expressions::Expression const& initialValue); + /*! * Retrieves whether the variable has an initial value. */ diff --git a/src/storage/jani/VariableSet.cpp b/src/storage/jani/VariableSet.cpp index 8afed1b1c..e4d37957d 100644 --- a/src/storage/jani/VariableSet.cpp +++ b/src/storage/jani/VariableSet.cpp @@ -9,7 +9,7 @@ namespace storm { namespace detail { - VariableSetIterator::VariableSetIterator(VariableSet const& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator) : variableSet(variableSet), it(initialIterator) { + VariableSetIterator::VariableSetIterator(VariableSet& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator) : variableSet(variableSet), it(initialIterator) { // Intentionally left empty. } @@ -23,7 +23,7 @@ namespace storm { return *this; } - Variable const& VariableSetIterator::operator*() { + Variable& VariableSetIterator::operator*() { if (it.which() == 0) { return *boost::get<bool_iter>(it); } else if (it.which() == 1) { @@ -61,37 +61,117 @@ namespace storm { } } - IntegerVariables::IntegerVariables(VariableSet const& variableSet) : variableSet(variableSet) { + ConstVariableSetIterator::ConstVariableSetIterator(VariableSet const& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator) : variableSet(variableSet), it(initialIterator) { // Intentionally left empty. } - VariableSetIterator IntegerVariables::begin() const { + ConstVariableSetIterator& ConstVariableSetIterator::operator++() { + incrementIterator(); + return *this; + } + + ConstVariableSetIterator& ConstVariableSetIterator::operator++(int) { + incrementIterator(); + return *this; + } + + Variable const& ConstVariableSetIterator::operator*() { + if (it.which() == 0) { + return *boost::get<bool_iter>(it); + } else if (it.which() == 1) { + return *boost::get<bint_iter>(it); + } else { + return *boost::get<int_iter>(it); + } + } + + bool ConstVariableSetIterator::operator==(ConstVariableSetIterator const& other) const { + return this->it == other.it; + } + + bool ConstVariableSetIterator::operator!=(ConstVariableSetIterator const& other) const { + return this->it != other.it; + } + + void ConstVariableSetIterator::incrementIterator() { + if (it.which() == 0) { + bool_iter& tmp = boost::get<bool_iter>(it); + if (tmp != variableSet.getBooleanVariables().end()) { + ++tmp; + } else { + it = variableSet.getBoundedIntegerVariables().begin(); + } + } else if (it.which() == 1) { + bint_iter& tmp = boost::get<bint_iter>(it); + if (tmp != variableSet.getBoundedIntegerVariables().end()) { + ++tmp; + } else { + it = variableSet.getUnboundedIntegerVariables().begin(); + } + } else { + ++boost::get<int_iter>(it); + } + } + + IntegerVariables::IntegerVariables(VariableSet& variableSet) : variableSet(variableSet) { + // Intentionally left empty. + } + + VariableSetIterator IntegerVariables::begin() { return VariableSetIterator(variableSet, variableSet.getBoundedIntegerVariables().begin()); } - VariableSetIterator IntegerVariables::end() const { + VariableSetIterator IntegerVariables::end() { return VariableSetIterator(variableSet, variableSet.getUnboundedIntegerVariables().end()); } + + ConstIntegerVariables::ConstIntegerVariables(VariableSet const& variableSet) : variableSet(variableSet) { + // Intentionally left empty. + } + + ConstVariableSetIterator ConstIntegerVariables::begin() const { + return ConstVariableSetIterator(variableSet, variableSet.getBoundedIntegerVariables().begin()); + } + + ConstVariableSetIterator ConstIntegerVariables::end() const { + return ConstVariableSetIterator(variableSet, variableSet.getUnboundedIntegerVariables().end()); + } } VariableSet::VariableSet() { // Intentionally left empty. } - std::vector<BooleanVariable> const& VariableSet::getBooleanVariables() const { + std::vector<BooleanVariable>& VariableSet::getBooleanVariables() { return booleanVariables; } + std::vector<BooleanVariable> const& VariableSet::getBooleanVariables() const { + return booleanVariables; + } + + std::vector<BoundedIntegerVariable>& VariableSet::getBoundedIntegerVariables() { + return boundedIntegerVariables; + } + std::vector<BoundedIntegerVariable> const& VariableSet::getBoundedIntegerVariables() const { return boundedIntegerVariables; } - + + std::vector<UnboundedIntegerVariable>& VariableSet::getUnboundedIntegerVariables() { + return unboundedIntegerVariables; + } + std::vector<UnboundedIntegerVariable> const& VariableSet::getUnboundedIntegerVariables() const { return unboundedIntegerVariables; } - - detail::IntegerVariables VariableSet::getIntegerVariables() const { - return detail::IntegerVariables(*this); + + VariableSet::IntegerVariables VariableSet::getIntegerVariables() { + return IntegerVariables(*this); + } + + VariableSet::ConstIntegerVariables VariableSet::getIntegerVariables() const { + return ConstIntegerVariables(*this); } void VariableSet::addBooleanVariable(BooleanVariable const& variable) { @@ -124,15 +204,23 @@ namespace storm { STORM_LOG_THROW(it != nameToVariable.end(), storm::exceptions::InvalidArgumentException, "Unable to retrieve unknown variable '" << name << "'."); return getVariable(it->second); } - - detail::VariableSetIterator VariableSet::begin() const { - return detail::VariableSetIterator(*this, booleanVariables.begin()); + + VariableSet::iterator VariableSet::begin() { + return iterator(*this, booleanVariables.begin()); } - - detail::VariableSetIterator VariableSet::end() const { - return detail::VariableSetIterator(*this, unboundedIntegerVariables.end()); + + VariableSet::const_iterator VariableSet::begin() const { + return const_iterator(*this, booleanVariables.begin()); } + VariableSet::iterator VariableSet::end() { + return iterator(*this, unboundedIntegerVariables.end()); + } + + VariableSet::const_iterator VariableSet::end() const { + return const_iterator(*this, unboundedIntegerVariables.end()); + } + Variable const& VariableSet::getVariable(storm::expressions::Variable const& variable) const { auto it = variableToVariable.find(variable); STORM_LOG_THROW(it != variableToVariable.end(), storm::exceptions::InvalidArgumentException, "Unable to retrieve unknown variable '" << variable.getName() << "'."); diff --git a/src/storage/jani/VariableSet.h b/src/storage/jani/VariableSet.h index d5a03a345..8c8ec6815 100644 --- a/src/storage/jani/VariableSet.h +++ b/src/storage/jani/VariableSet.h @@ -18,21 +18,21 @@ namespace storm { class VariableSetIterator { private: - typedef std::vector<BooleanVariable>::const_iterator bool_iter; - typedef std::vector<BoundedIntegerVariable>::const_iterator bint_iter; - typedef std::vector<UnboundedIntegerVariable>::const_iterator int_iter; + typedef std::vector<BooleanVariable>::iterator bool_iter; + typedef std::vector<BoundedIntegerVariable>::iterator bint_iter; + typedef std::vector<UnboundedIntegerVariable>::iterator int_iter; public: /*! * Creates an iterator over all variables. */ - VariableSetIterator(VariableSet const& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator); + VariableSetIterator(VariableSet& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator); // Methods to advance the iterator. VariableSetIterator& operator++(); VariableSetIterator& operator++(int); - Variable const& operator*(); + Variable& operator*(); bool operator==(VariableSetIterator const& other) const; bool operator!=(VariableSetIterator const& other) const; @@ -42,25 +42,76 @@ namespace storm { void incrementIterator(); // The underlying variable set. - VariableSet const& variableSet; + VariableSet& variableSet; // The current iterator position. boost::variant<bool_iter, bint_iter, int_iter> it; }; + class ConstVariableSetIterator { + private: + typedef std::vector<BooleanVariable>::const_iterator bool_iter; + typedef std::vector<BoundedIntegerVariable>::const_iterator bint_iter; + typedef std::vector<UnboundedIntegerVariable>::const_iterator int_iter; + + public: + /*! + * Creates an iterator over all variables. + */ + ConstVariableSetIterator(VariableSet const& variableSet, boost::variant<bool_iter, bint_iter, int_iter> initialIterator); + + // Methods to advance the iterator. + ConstVariableSetIterator& operator++(); + ConstVariableSetIterator& operator++(int); + + Variable const& operator*(); + + bool operator==(ConstVariableSetIterator const& other) const; + bool operator!=(ConstVariableSetIterator const& other) const; + + private: + // Moves the iterator to the next position. + void incrementIterator(); + + // The underlying variable set. + VariableSet const& variableSet; + + // The current iterator position. + boost::variant<bool_iter, bint_iter, int_iter> it; + }; + class IntegerVariables { public: - IntegerVariables(VariableSet const& variableSet); + IntegerVariables(VariableSet& variableSet); /*! * Retrieves an iterator to all integer variables (bounded and unbounded) in the variable set. */ - VariableSetIterator begin() const; + VariableSetIterator begin(); /*! * Retrieves the end iterator to all integer variables (bounded and unbounded) in the variable set. */ - VariableSetIterator end() const; + VariableSetIterator end(); + + private: + // The underlying variable set. + VariableSet& variableSet; + }; + + class ConstIntegerVariables { + public: + ConstIntegerVariables(VariableSet const& variableSet); + + /*! + * Retrieves an iterator to all integer variables (bounded and unbounded) in the variable set. + */ + ConstVariableSetIterator begin() const; + + /*! + * Retrieves the end iterator to all integer variables (bounded and unbounded) in the variable set. + */ + ConstVariableSetIterator end() const; private: // The underlying variable set. @@ -72,30 +123,55 @@ namespace storm { public: friend class detail::VariableSetIterator; + typedef detail::VariableSetIterator iterator; + typedef detail::ConstVariableSetIterator const_iterator; + typedef detail::IntegerVariables IntegerVariables; + typedef detail::ConstIntegerVariables ConstIntegerVariables; + /*! * Creates an empty variable set. */ VariableSet(); + /*! + * Retrieves the boolean variables in this set. + */ + std::vector<BooleanVariable>& getBooleanVariables(); + /*! * Retrieves the boolean variables in this set. */ std::vector<BooleanVariable> const& getBooleanVariables() const; + /*! + * Retrieves the bounded integer variables in this set. + */ + std::vector<BoundedIntegerVariable>& getBoundedIntegerVariables(); + /*! * Retrieves the bounded integer variables in this set. */ std::vector<BoundedIntegerVariable> const& getBoundedIntegerVariables() const; + /*! + * Retrieves the unbounded integer variables in this set. + */ + std::vector<UnboundedIntegerVariable>& getUnboundedIntegerVariables(); + /*! * Retrieves the unbounded integer variables in this set. */ std::vector<UnboundedIntegerVariable> const& getUnboundedIntegerVariables() const; + + /*! + * Retrieves an iterable object to all integer (bounded and unbounded) variables in the variable set. + */ + IntegerVariables getIntegerVariables(); /*! * Retrieves an iterable object to all integer (bounded and unbounded) variables in the variable set. */ - detail::IntegerVariables getIntegerVariables() const; + ConstIntegerVariables getIntegerVariables() const; /*! * Adds the given boolean variable to this set. @@ -135,13 +211,23 @@ namespace storm { /*! * Retrieves an iterator to the variables in this set. */ - detail::VariableSetIterator begin() const; + iterator begin(); + + /*! + * Retrieves an iterator to the variables in this set. + */ + const_iterator begin() const; /*! * Retrieves the end iterator to the variables in this set. */ - detail::VariableSetIterator end() const; - + iterator end(); + + /*! + * Retrieves the end iterator to the variables in this set. + */ + const_iterator end() const; + private: /// The boolean variables in this set. std::vector<BooleanVariable> booleanVariables; diff --git a/src/utility/jani.cpp b/src/utility/jani.cpp new file mode 100644 index 000000000..6a91f14a7 --- /dev/null +++ b/src/utility/jani.cpp @@ -0,0 +1,72 @@ +#include "src/utility/jani.h" + +#include <boost/algorithm/string.hpp> + +#include "src/storage/expressions/ExpressionManager.h" +#include "src/storage/jani/Model.h" + +#include "src/utility/macros.h" +#include "src/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace utility { + namespace jani { + + std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitionString(storm::jani::Model const& model, std::string const& constantDefinitionString) { + std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions; + std::set<storm::expressions::Variable> 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. + std::size_t positionOfAssignmentOperator = definition.find('='); + STORM_LOG_THROW(positionOfAssignmentOperator != std::string::npos, 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 (model.hasConstant(constantName)) { + // Get the actual constant and check whether it's in fact undefined. + auto const& constant = model.getConstant(constantName); + storm::expressions::Variable variable = constant.getExpressionVariable(); + STORM_LOG_THROW(!constant.isDefined(), storm::exceptions::InvalidArgumentException, "Illegally trying to define already defined constant '" << constantName <<"'."); + STORM_LOG_THROW(definedConstants.find(variable) == definedConstants.end(), storm::exceptions::InvalidArgumentException, "Illegally trying to define constant '" << constantName <<"' twice."); + definedConstants.insert(variable); + + if (constant.getType().isBooleanType()) { + if (value == "true") { + constantDefinitions[variable] = model.getExpressionManager().boolean(true); + } else if (value == "false") { + constantDefinitions[variable] = model.getExpressionManager().boolean(false); + } else { + throw storm::exceptions::InvalidArgumentException() << "Illegal value for boolean constant: " << value << "."; + } + } else if (constant.getType().isIntegerType()) { + int_fast64_t integerValue = std::stoi(value); + constantDefinitions[variable] = model.getExpressionManager().integer(integerValue); + } else if (constant.getType().isRationalType()) { + double doubleValue = std::stod(value); + constantDefinitions[variable] = model.getExpressionManager().rational(doubleValue); + } + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal constant definition string: unknown undefined constant '" << constantName << "'."); + } + } + } + + return constantDefinitions; + } + + } + } +} \ No newline at end of file diff --git a/src/utility/jani.h b/src/utility/jani.h new file mode 100644 index 000000000..08bc75b91 --- /dev/null +++ b/src/utility/jani.h @@ -0,0 +1,23 @@ +#pragma once + +#include <map> + +namespace storm { + namespace expressions { + class Variable; + class Expression; + } + + namespace jani { + class Model; + } + + namespace utility { + namespace jani { + + std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitionString(storm::jani::Model const& model, std::string const& constantDefinitionString); + + } + } +} +