Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ImcaMarkovAutomatonParserGrammar.cpp
Go to the documentation of this file.
2
4#include "storm/io/file.h"
6
7namespace storm {
8namespace parser {
9
10template<typename ValueType, typename StateType>
12 : ImcaParserGrammar<ValueType, StateType>::base_type(start),
13 options(options),
14 numStates(0),
15 numChoices(0),
16 numTransitions(0),
17 hasStateReward(false),
18 hasActionReward(false) {
19 initialize();
20}
21
22template<typename ValueType, typename StateType>
23void ImcaParserGrammar<ValueType, StateType>::initialize() {
24 value = qi::double_[qi::_val = qi::_1];
25 value.name("value");
26
27 // We assume here that imca files are alphanumeric strings, If we restrict ourselves to the 's12345' representation, we could also do:
28 // state = (qi::lit("s") > qi::ulong_)[qi::_val = qi::_1];
29 state = qi::as_string[qi::raw[qi::lexeme[(qi::alnum | qi::char_('_')) % qi::eps]]]
30 [qi::_val = phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::getStateIndex, phoenix::ref(*this), qi::_1)];
31 state.name("state");
32
33 reward = (-qi::lit("R") >> value)[qi::_val = qi::_1];
34 reward.name("reward");
35
36 transition = (qi::lit("*") >> state >>
37 value)[qi::_val = phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::createStateValuePair, phoenix::ref(*this), qi::_1, qi::_2)];
38 transition.name("transition");
39
40 choicelabel = qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')) | qi::lit("!"))]]];
41 choicelabel.name("choicelabel");
42
43 choice =
44 (state >> choicelabel >> -reward >>
45 *(transition >>
46 qi::eps))[phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::addChoiceToStateBehavior, phoenix::ref(*this), qi::_1, qi::_2, qi::_4, qi::_3)];
47 choice.name("choice");
48
49 transitions = qi::lit("#TRANSITIONS") >> *(choice);
50 transitions.name("TRANSITIONS");
51
52 initials =
53 qi::lit("#INITIALS") >> *((state >> qi::eps)[phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::addInitialState, phoenix::ref(*this), qi::_1)]);
54 initials.name("INITIALS");
55
56 goals = qi::lit("#GOALS") >> *((state >> qi::eps)[phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::addGoalState, phoenix::ref(*this), qi::_1)]);
57 goals.name("GOALS");
58
59 start = (initials >> goals >> transitions)[qi::_val = phoenix::bind(&ImcaParserGrammar<ValueType, StateType>::createModelComponents, phoenix::ref(*this))];
60 start.name("start");
61}
62
63template<typename ValueType, typename StateType>
64StateType ImcaParserGrammar<ValueType, StateType>::getStateIndex(std::string const& stateString) {
65 auto it = stateIndices.find(stateString);
66 if (it == stateIndices.end()) {
67 this->stateIndices.emplace_hint(it, stateString, numStates);
68 ++numStates;
69 initialStates.grow(numStates);
70 goalStates.grow(numStates);
71 markovianStates.grow(numStates);
72 stateBehaviors.resize(numStates);
73 return numStates - 1;
74 } else {
75 return it->second;
76 }
77}
78
79template<typename ValueType, typename StateType>
80std::pair<StateType, ValueType> ImcaParserGrammar<ValueType, StateType>::createStateValuePair(StateType const& state, ValueType const& value) {
81 return std::pair<StateType, ValueType>(state, value);
82}
83
84template<typename ValueType, typename StateType>
85void ImcaParserGrammar<ValueType, StateType>::addInitialState(StateType const& state) {
86 initialStates.set(state);
87}
88
89template<typename ValueType, typename StateType>
90void ImcaParserGrammar<ValueType, StateType>::addGoalState(StateType const& state) {
91 goalStates.set(state);
92}
93
94template<typename ValueType, typename StateType>
95void ImcaParserGrammar<ValueType, StateType>::addChoiceToStateBehavior(StateType const& state, std::string const& label,
96 std::vector<std::pair<StateType, ValueType>> const& transitions,
97 boost::optional<ValueType> const& reward) {
98 bool isMarkovian = label == "!";
99 storm::generator::Choice<ValueType, StateType> choice(0, isMarkovian);
100 STORM_LOG_THROW(!transitions.empty(), storm::exceptions::WrongFormatException, "Empty choice defined for state s" << state << ".");
101 if (options.buildChoiceLabels && !isMarkovian) {
102 choice.addLabel(label);
103 }
104 if (reward && !isMarkovian) {
105 hasActionReward = true;
106 choice.addReward(reward.get());
107 }
108 for (auto const& t : transitions) {
109 STORM_LOG_THROW(t.second > storm::utility::zero<ValueType>(), storm::exceptions::WrongFormatException,
110 "Probabilities and rates have to be positive. got " << t.second << " at state s" << state << ".");
111 choice.addProbability(t.first, t.second);
112 }
113 STORM_LOG_THROW(isMarkovian || storm::utility::isOne(choice.getTotalMass()), storm::exceptions::WrongFormatException,
114 "Probability for choice " << label << " on state s" << state << " does not sum up to one.");
115
116 ++numChoices;
117 numTransitions += choice.size();
118 auto& behavior = stateBehaviors[state];
119 behavior.setExpanded(true);
120 behavior.addChoice(std::move(choice));
121 if (isMarkovian) {
122 markovianStates.set(state);
123 if (reward) {
124 hasStateReward = true;
125 behavior.addStateReward(reward.get());
126 }
127 }
128}
129
130template<typename ValueType, typename StateType>
131storm::storage::sparse::ModelComponents<ValueType> ImcaParserGrammar<ValueType, StateType>::createModelComponents() {
132 // Prepare the statelabeling
133 initialStates.resize(numStates);
134 goalStates.resize(numStates);
135 markovianStates.resize(numStates);
136 storm::models::sparse::StateLabeling stateLabeling(numStates);
137 stateLabeling.addLabel("init", std::move(initialStates));
138 stateLabeling.addLabel("goal", std::move(goalStates));
139
140 // Fix deadlocks (if required)
141 STORM_LOG_ASSERT(stateBehaviors.size() == numStates, "State behavior count mismatch.");
142 if (options.fixDeadlocks) {
143 StateType state = 0;
144 for (auto& behavior : stateBehaviors) {
145 if (!behavior.wasExpanded()) {
146 storm::generator::Choice<ValueType, StateType> choice(0, true);
147 choice.addProbability(state, storm::utility::one<ValueType>());
148 behavior.setExpanded(true);
149 behavior.addChoice(std::move(choice));
150 markovianStates.set(state);
151 ++numChoices;
152 ++numTransitions;
153 }
154 ++state;
155 }
156 }
157
158 // Build the transition matrix together with exit rates, reward models, and choice labeling
159 storm::storage::SparseMatrixBuilder<ValueType> matrixBuilder(numChoices, numStates, numTransitions, true, true, numStates);
160 std::vector<ValueType> exitRates;
161 exitRates.reserve(numStates);
162 std::optional<std::vector<ValueType>> stateRewards, actionRewards;
163 if (hasStateReward) {
164 stateRewards = std::vector<ValueType>(numStates, storm::utility::zero<ValueType>());
165 }
166 if (hasActionReward) {
167 actionRewards = std::vector<ValueType>(numChoices, storm::utility::zero<ValueType>());
168 }
169 std::optional<storm::models::sparse::ChoiceLabeling> choiceLabeling;
170 if (options.buildChoiceLabels) {
171 choiceLabeling = storm::models::sparse::ChoiceLabeling(numChoices);
172 }
173 StateType state = 0;
174 StateType row = 0;
175 for (auto const& behavior : stateBehaviors) {
176 matrixBuilder.newRowGroup(row);
177 if (!behavior.getStateRewards().empty()) {
178 STORM_LOG_ASSERT(behavior.getStateRewards().size() == 1, "Expected single state reward.");
179 stateRewards.value()[state] = behavior.getStateRewards().front();
180 }
181 if (markovianStates.get(state)) {
182 // For Markovian states, the Markovian choice has to be the first one in the resulting transition matrix.
183 bool markovianChoiceFound = false;
184 for (auto const& choice : behavior) {
185 if (choice.isMarkovian()) {
186 STORM_LOG_THROW(!markovianChoiceFound, storm::exceptions::WrongFormatException,
187 "Multiple Markovian choices defined for state " << state << ".");
188 markovianChoiceFound = true;
189 if (!choice.getRewards().empty()) {
190 STORM_LOG_ASSERT(choice.getRewards().size() == 1, "Expected exactly one reward per choice.");
191 actionRewards.value()[row] = choice.getRewards().front();
192 }
193 if (options.buildChoiceLabels && choice.hasLabels()) {
194 STORM_LOG_ASSERT(choice.getLabels().size() == 1, "Expected exactly one label per choice.");
195 std::string const& label = *choice.getLabels().begin();
196 if (!choiceLabeling->containsLabel(label)) {
197 choiceLabeling->addLabel(label);
198 }
199 choiceLabeling->addLabelToChoice(label, row);
200 }
201 exitRates.push_back(choice.getTotalMass());
202 for (auto const& transition : choice) {
203 matrixBuilder.addNextValue(row, transition.first, static_cast<ValueType>(transition.second / exitRates.back()));
204 }
205 ++row;
206 }
207 }
208 } else {
209 exitRates.push_back(storm::utility::zero<ValueType>());
210 }
211 // Now add all probabilistic choices.
212 for (auto const& choice : behavior) {
213 if (!choice.isMarkovian()) {
214 if (!choice.getRewards().empty()) {
215 STORM_LOG_ASSERT(choice.getRewards().size() == 1, "Expected exactly one reward per choice.");
216 actionRewards.value()[row] = choice.getRewards().front();
217 }
218 if (options.buildChoiceLabels && choice.hasLabels()) {
219 STORM_LOG_ASSERT(choice.getLabels().size() == 1, "Expected exactly one label per choice.");
220 std::string const& label = *choice.getLabels().begin();
221 if (!choiceLabeling->containsLabel(label)) {
222 choiceLabeling->addLabel(label);
223 }
224 choiceLabeling->addLabelToChoice(label, row);
225 }
226 for (auto const& transition : choice) {
227 matrixBuilder.addNextValue(row, transition.first, transition.second);
228 }
229 ++row;
230 }
231 }
232 ++state;
233 }
234
235 // Finalize the model components
236 std::unordered_map<std::string, storm::models::sparse::StandardRewardModel<ValueType>> rewardModel;
237 if (hasStateReward || hasActionReward) {
238 rewardModel.insert(std::make_pair("", storm::models::sparse::StandardRewardModel<ValueType>(stateRewards, actionRewards)));
239 }
240 storm::storage::sparse::ModelComponents<ValueType> components(matrixBuilder.build(), std::move(stateLabeling), std::move(rewardModel), false,
241 std::move(markovianStates));
242 components.exitRates = std::move(exitRates);
243 components.choiceLabeling = std::move(choiceLabeling);
244
245 return components;
246}
247
248template class ImcaParserGrammar<double>;
249} // namespace parser
250} // namespace storm
ImcaParserGrammar(ExplicitModelParserOptions const &options=ExplicitModelParserOptions())
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
SFTBDDChecker::ValueType ValueType
Contains all file parsers and helper classes.
bool isOne(ValueType const &a)
Definition constants.cpp:37
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19