Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
PrismNextStateGenerator.cpp
Go to the documentation of this file.
2
3#include <boost/any.hpp>
4
20
21namespace storm {
22namespace generator {
23
24template<typename ValueType, typename StateType>
26 std::shared_ptr<ActionMask<ValueType, StateType>> const& mask)
27 : PrismNextStateGenerator<ValueType, StateType>(program.substituteConstantsFormulas(), options, mask, false) {
28 // Intentionally left empty.
30
31template<typename ValueType, typename StateType>
33 std::shared_ptr<ActionMask<ValueType, StateType>> const& mask, bool)
34 : NextStateGenerator<ValueType, StateType>(program.getManager(), options, mask), program(program), rewardModels(), hasStateActionRewards(false) {
35 STORM_LOG_TRACE("Creating next-state generator for PRISM program: " << program);
36 STORM_LOG_THROW(!this->program.specifiesSystemComposition(), storm::exceptions::WrongFormatException,
37 "The explicit next-state generator currently does not support custom system compositions.");
38 STORM_LOG_THROW(storm::IsIntervalType<ValueType> || !this->program.hasIntervalUpdates(), storm::exceptions::WrongFormatException,
39 "The provided PRISM program contains interval updates, which are not supported by the chosen value type.");
41 // Only after checking validity of the program, we initialize the variable information.
42 this->checkValid();
43 this->variableInformation = VariableInformation(program, options.getReservedBitsForUnboundedVariables(), options.isAddOutOfBoundsStateSet());
44 this->initializeSpecialStates();
45
46 // Create a proper evaluator.
47 this->evaluator = std::make_unique<storm::expressions::ExpressionEvaluator<BaseValueType>>(program.getManager());
48
49 if (this->options.isBuildAllRewardModelsSet()) {
50 for (auto const& rewardModel : this->program.getRewardModels()) {
51 rewardModels.push_back(rewardModel);
52 }
53 } else {
54 // Extract the reward models from the program based on the names we were given.
55 for (auto const& rewardModelName : this->options.getRewardModelNames()) {
56 if (this->program.hasRewardModel(rewardModelName)) {
57 rewardModels.push_back(this->program.getRewardModel(rewardModelName));
58 } else {
59 STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException,
60 "Cannot build unknown reward model '" << rewardModelName << "'.");
61 STORM_LOG_THROW(this->program.getNumberOfRewardModels() == 1, storm::exceptions::InvalidArgumentException,
62 "Reference to standard reward model is ambiguous.");
63 }
64 }
65
66 // If no reward model was yet added, but there was one that was given in the options, we try to build the
67 // standard reward model.
68 if (rewardModels.empty() && !this->options.getRewardModelNames().empty()) {
69 rewardModels.push_back(this->program.getRewardModel(0));
70 }
71 }
72
73 // Determine whether any reward model has state action rewards.
74 for (auto const& rewardModel : rewardModels) {
75 hasStateActionRewards |= rewardModel.get().hasStateActionRewards();
76 }
77
78 // If there are terminal states we need to handle, we now need to translate all labels to expressions.
79 if (this->options.hasTerminalStates()) {
80 for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
81 if (expressionOrLabelAndBool.first.isExpression()) {
82 this->terminalStates.push_back(std::make_pair(expressionOrLabelAndBool.first.getExpression(), expressionOrLabelAndBool.second));
83 } else {
84 if (program.hasLabel(expressionOrLabelAndBool.first.getLabel())) {
85 this->terminalStates.push_back(
86 std::make_pair(this->program.getLabelExpression(expressionOrLabelAndBool.first.getLabel()), expressionOrLabelAndBool.second));
87 } else {
88 // If the label is not present in the program and is not a special one, we raise an error.
89 STORM_LOG_THROW(this->isSpecialLabel(expressionOrLabelAndBool.first.getLabel()), storm::exceptions::InvalidArgumentException,
90 "Terminal states refer to illegal label '" << expressionOrLabelAndBool.first.getLabel() << "'.");
91 }
92 }
93 }
94 }
95
97 moduleIndexToPlayerIndexMap = program.buildModuleIndexToPlayerIndexMap();
98 actionIndexToPlayerIndexMap = program.buildActionIndexToPlayerIndexMap();
99 }
100}
101
102template<typename ValueType, typename StateType>
104 // We can handle all valid prism programs (except for PTAs)
106}
107
108template<typename ValueType, typename StateType>
110 // If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.
111 if (!std::is_same<ValueType, storm::RationalFunction>::value && program.hasUndefinedConstants()) {
112 std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants();
113 std::stringstream stream;
114 bool printComma = false;
115 for (auto const& constant : undefinedConstants) {
116 if (printComma) {
117 stream << ", ";
118 } else {
119 printComma = true;
120 }
121 stream << constant.get().getName() << " (" << constant.get().getType() << ")";
122 }
123 stream << ".";
124 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str());
125 } else if (std::is_same<ValueType, storm::RationalFunction>::value && !program.undefinedConstantsAreGraphPreserving()) {
126 auto undef = program.getUndefinedConstantsAsString();
127 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException,
128 "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, "
129 "which is not admitted. Undefined constants are: "
130 << undef);
131 }
132}
133
134template<typename ValueType, typename StateType>
136 switch (program.getModelType()) {
138 return ModelType::DTMC;
140 return ModelType::CTMC;
142 return ModelType::MDP;
144 return ModelType::MA;
146 return ModelType::POMDP;
148 return ModelType::SMG;
149 default:
150 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Invalid model type.");
151 }
152}
153
154template<typename ValueType, typename StateType>
158
159template<typename ValueType, typename StateType>
163
164template<typename ValueType, typename StateType>
168
169template<typename ValueType, typename StateType>
171 std::vector<StateType> initialStateIndices;
172
173 // If all states are initial, we can simplify the enumeration substantially.
174 if (program.hasInitialConstruct() && program.getInitialStatesExpression().isTrue()) {
175 // Create vectors holding all possible values
176 std::vector<std::vector<uint64_t>> allValues;
177 for (auto const& intVar : this->variableInformation.integerVariables) {
178 STORM_LOG_ASSERT(intVar.lowerBound <= intVar.upperBound, "Expecting variable with non-empty set of possible values.");
179 // The value of integer variables is shifted so that 0 is always the smallest possible value
180 allValues.push_back(storm::utility::vector::buildVectorForRange<uint64_t>(static_cast<uint64_t>(0), intVar.upperBound + 1 - intVar.lowerBound));
181 }
182 uint64_t intEndIndex = allValues.size();
183 // For boolean variables we consider the values 0 and 1.
184 allValues.resize(allValues.size() + this->variableInformation.booleanVariables.size(),
185 std::vector<uint64_t>({static_cast<uint64_t>(0), static_cast<uint64_t>(1)}));
186
187 std::vector<std::vector<uint64_t>::const_iterator> its;
188 std::vector<std::vector<uint64_t>::const_iterator> ites;
189 for (auto const& valVec : allValues) {
190 its.push_back(valVec.cbegin());
191 ites.push_back(valVec.cend());
192 }
193
194 // Now create an initial state for each combination of values
195 CompressedState initialState(this->variableInformation.getTotalBitOffset(true));
197 its, ites,
198 [this, &initialState, &intEndIndex](uint64_t index, uint64_t value) {
199 // Set the value for the variable corresponding to the given index
200 if (index < intEndIndex) {
201 // Integer variable
202 auto const& intVar = this->variableInformation.integerVariables[index];
203 initialState.setFromInt(intVar.bitOffset, intVar.bitWidth, value);
204 } else {
205 // Boolean variable
206 STORM_LOG_ASSERT(index - intEndIndex < this->variableInformation.booleanVariables.size(), "Unexpected index");
207 auto const& boolVar = this->variableInformation.booleanVariables[index - intEndIndex];
208 STORM_LOG_ASSERT(value <= 1u, "Unexpected value for boolean variable.");
209 initialState.set(boolVar.bitOffset, static_cast<bool>(value));
210 }
211 },
212 [&stateToIdCallback, &initialStateIndices, &initialState]() {
213 // Register initial state.
214 StateType id = stateToIdCallback(initialState);
215 initialStateIndices.push_back(id);
216 return true; // Keep on exploring
217 });
218 STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using brute force enumeration.");
219 } else {
220 // Prepare an SMT solver to enumerate all initial states.
222 std::unique_ptr<storm::solver::SmtSolver> solver = factory.create(program.getManager());
223
224 std::vector<storm::expressions::Expression> rangeExpressions = program.getAllRangeExpressions();
225 for (auto const& expression : rangeExpressions) {
226 solver->add(expression);
227 }
228 solver->add(program.getInitialStatesExpression());
229
230 // Proceed ss long as the solver can still enumerate initial states.
231 while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) {
232 // Create fresh state.
233 CompressedState initialState(this->variableInformation.getTotalBitOffset(true));
234
235 // Read variable assignment from the solution of the solver. Also, create an expression we can use to
236 // prevent the variable assignment from being enumerated again.
237 storm::expressions::Expression blockingExpression;
238 std::shared_ptr<storm::solver::SmtSolver::ModelReference> model = solver->getModel();
239 for (auto const& booleanVariable : this->variableInformation.booleanVariables) {
240 bool variableValue = model->getBooleanValue(booleanVariable.variable);
241 storm::expressions::Expression localBlockingExpression = variableValue ? !booleanVariable.variable : booleanVariable.variable;
242 blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression;
243 initialState.set(booleanVariable.bitOffset, variableValue);
244 }
245 for (auto const& integerVariable : this->variableInformation.integerVariables) {
246 int_fast64_t variableValue = model->getIntegerValue(integerVariable.variable);
247 storm::expressions::Expression localBlockingExpression = integerVariable.variable != model->getManager().integer(variableValue);
248 blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression;
249 initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth,
250 static_cast<uint_fast64_t>(variableValue - integerVariable.lowerBound));
251 }
252
253 // Register initial state and return it.
254 StateType id = stateToIdCallback(initialState);
255 initialStateIndices.push_back(id);
256
257 // Block the current initial state to search for the next one.
258 if (!blockingExpression.isInitialized()) {
259 break;
260 }
261 solver->add(blockingExpression);
262 }
263
264 STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using SMT solving.");
265 }
266
267 return initialStateIndices;
268}
269
270template<typename ValueType, typename StateType>
272 // Prepare the result, in case we return early.
274
275 // First, construct the state rewards, as we may return early if there are no choices later and we already
276 // need the state rewards then.
277 for (auto const& rewardModel : rewardModels) {
278 ValueType stateRewardValue = storm::utility::zero<ValueType>();
279 if (rewardModel.get().hasStateRewards()) {
280 for (auto const& stateReward : rewardModel.get().getStateRewards()) {
281 if (this->evaluator->asBool(stateReward.getStatePredicateExpression())) {
282 stateRewardValue += ValueType(this->evaluator->asRational(stateReward.getRewardValueExpression()));
283 }
284 }
285 }
286 result.addStateReward(stateRewardValue);
287 }
288
289 // If a terminal expression was set, we must not expand this state
290 if (!this->terminalStates.empty()) {
291 for (auto const& expressionBool : this->terminalStates) {
292 if (this->evaluator->asBool(expressionBool.first) == expressionBool.second) {
293 if (!isPartiallyObservable()) {
294 // If the model is not partially observable, return.
295 return result;
296 } else {
297 // for partially observable models, we need to add self-loops for all enabled actions.
298 result.setExpanded();
299 std::vector<Choice<ValueType>> allChoices = getSelfLoopsForAllActions(*this->state, stateToIdCallback);
300 if (allChoices.size() != 0) {
301 for (auto& choice : allChoices) {
302 result.addChoice(std::move(choice));
303 }
304
305 this->postprocess(result);
306 }
307 return result;
308 }
309 }
310 }
311 }
312
313 // Get all choices for the state.
314 result.setExpanded();
315
316 std::vector<Choice<ValueType>> allChoices;
317 if (this->getOptions().isApplyMaximalProgressAssumptionSet()) {
318 // First explore only edges without a rate
319 allChoices = getAsynchronousChoices(*this->state, stateToIdCallback, CommandFilter::Probabilistic);
320 addSynchronousChoices(allChoices, *this->state, stateToIdCallback, CommandFilter::Probabilistic);
321 if (allChoices.empty()) {
322 // Expand the Markovian edges if there are no probabilistic ones.
323 allChoices = getAsynchronousChoices(*this->state, stateToIdCallback, CommandFilter::Markovian);
324 addSynchronousChoices(allChoices, *this->state, stateToIdCallback, CommandFilter::Markovian);
325 }
326 } else {
327 allChoices = getAsynchronousChoices(*this->state, stateToIdCallback);
328 addSynchronousChoices(allChoices, *this->state, stateToIdCallback);
329 }
330
331 // If there is not a single choice, we return immediately, because the state has no behavior (other than
332 // the state reward).
333 if (allChoices.empty()) {
334 return result;
335 }
336
337 // If the model is a deterministic model, we need to fuse the choices into one.
338 if (this->isDeterministicModel() && allChoices.size() > 1) {
339 Choice<ValueType> globalChoice;
340
341 if (this->options.isAddOverlappingGuardLabelSet()) {
342 this->overlappingGuardStates->push_back(stateToIdCallback(*this->state));
343 }
344
345 // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
346 // this is equal to the number of choices, which is why we initialize it like this here.
347 ValueType const totalNumberOfChoices = storm::utility::convertNumber<ValueType, uint64_t>(allChoices.size());
348 ValueType totalExitRate = this->isDiscreteTimeModel() ? totalNumberOfChoices : storm::utility::zero<ValueType>();
349
350 // Iterate over all choices and combine the probabilities/rates into one choice.
351 for (auto const& choice : allChoices) {
352 for (auto const& stateProbabilityPair : choice) {
353 if (this->isDiscreteTimeModel()) {
354 globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second / totalNumberOfChoices);
355 } else {
356 globalChoice.addProbability(stateProbabilityPair.first, stateProbabilityPair.second);
357 }
358 }
359
360 if (hasStateActionRewards && !this->isDiscreteTimeModel()) {
361 totalExitRate += choice.getTotalMass();
362 }
363
364 if (this->options.isBuildChoiceLabelsSet() && choice.hasLabels()) {
365 globalChoice.addLabels(choice.getLabels());
366 }
367
368 if (this->options.isBuildChoiceOriginsSet() && choice.hasOriginData()) {
369 globalChoice.addOriginData(choice.getOriginData());
370 }
371 }
372
373 // Now construct the state-action reward for all selected reward models.
374 for (auto const& rewardModel : rewardModels) {
375 ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
376 if (rewardModel.get().hasStateActionRewards()) {
377 for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
378 for (auto const& choice : allChoices) {
379 if (stateActionReward.getActionIndex() == choice.getActionIndex() &&
380 this->evaluator->asBool(stateActionReward.getStatePredicateExpression())) {
381 stateActionRewardValue +=
382 ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression())) * choice.getTotalMass();
383 }
384 }
385 }
386 }
387 if (hasStateActionRewards) {
388 globalChoice.addReward(stateActionRewardValue / totalExitRate);
389 }
390 }
391
392 // Move the newly fused choice in place.
393 allChoices.clear();
394 allChoices.push_back(std::move(globalChoice));
395 }
396
397 // For SMG we check whether the state has a unique player
398 if (program.getModelType() == storm::prism::Program::ModelType::SMG && allChoices.size() > 1) {
399 auto choiceIt = allChoices.begin();
400 STORM_LOG_ASSERT(choiceIt->hasPlayerIndex(),
401 "State '" << this->stateToString(*this->state)
402 << "' features a choice without player index."); // This should have been catched while creating the choice already
403 storm::storage::PlayerIndex statePlayerIndex = choiceIt->getPlayerIndex();
405 "State '" << this->stateToString(*this->state)
406 << "' features a choice with invalid player index."); // This should have been catched while creating the choice already
407 for (++choiceIt; choiceIt != allChoices.end(); ++choiceIt) {
408 STORM_LOG_ASSERT(choiceIt->hasPlayerIndex(),
409 "State '" << this->stateToString(*this->state)
410 << "' features a choice without player index."); // This should have been catched while creating the choice already
411 STORM_LOG_ASSERT(choiceIt->getPlayerIndex() != storm::storage::INVALID_PLAYER_INDEX,
412 "State '" << this->stateToString(*this->state)
413 << "' features a choice with invalid player index."); // This should have been catched while creating the choice already
414 STORM_LOG_THROW(statePlayerIndex == choiceIt->getPlayerIndex(), storm::exceptions::WrongFormatException,
415 "The player for state '" << this->stateToString(*this->state) << "' is not unique. At least one choice is owned by player '"
416 << statePlayerIndex << "' while another is owned by player '" << choiceIt->getPlayerIndex() << "'.");
417 }
418 }
419
420 // Move all remaining choices in place.
421 for (auto& choice : allChoices) {
422 result.addChoice(std::move(choice));
423 }
424
425 this->postprocess(result);
426
427 return result;
428}
429
430template<typename ValueType, typename StateType>
434
435template<typename ValueType, typename StateType>
437 CompressedState newState(state);
438
439 // NOTE: the following process assumes that the assignments of the update are ordered in such a way that the
440 // assignments to boolean variables precede the assignments to all integer variables and that within the
441 // types, the assignments to variables are ordered (in ascending order) by the expression variables.
442 // This is guaranteed for PRISM models, by sorting the assignments as soon as an update is created.
443
444 auto assignmentIt = update.getAssignments().begin();
445 auto assignmentIte = update.getAssignments().end();
446
447 // Iterate over all boolean assignments and carry them out.
448 auto boolIt = this->variableInformation.booleanVariables.begin();
449 for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) {
450 while (assignmentIt->getVariable() != boolIt->variable) {
451 ++boolIt;
452 }
453 newState.set(boolIt->bitOffset, this->evaluator->asBool(assignmentIt->getExpression()));
454 }
455
456 // Iterate over all integer assignments and carry them out.
457 auto integerIt = this->variableInformation.integerVariables.begin();
458 for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) {
459 while (assignmentIt->getVariable() != integerIt->variable) {
460 ++integerIt;
461 }
462 int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getExpression());
463 if (this->options.isAddOutOfBoundsStateSet()) {
464 if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) {
465 return this->outOfBoundsState;
466 }
467 } else if (integerIt->forceOutOfBoundsCheck || this->options.isExplorationChecksSet()) {
468 STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException,
469 "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '"
470 << assignmentIt->getVariableName() << "'.");
471 STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException,
472 "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '"
473 << assignmentIt->getVariableName() << "'.");
474 }
475 newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound);
476 STORM_LOG_ASSERT(static_cast<int_fast64_t>(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue,
477 "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote "
478 << assignedValue << ").");
479 }
480
481 // Check that we processed all assignments.
482 STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed.");
483
484 return newState;
485}
486
489 typename std::set<uint_fast64_t>::const_iterator currentCommandIndexIt)
491 // Intentionally left empty
492 }
494 std::set<uint_fast64_t> const* commandIndicesPtr;
495 typename std::set<uint_fast64_t>::const_iterator currentCommandIndexIt;
496};
497
498template<typename ValueType, typename StateType>
499boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>
500PrismNextStateGenerator<ValueType, StateType>::getActiveCommandsByActionIndex(uint_fast64_t const& actionIndex, CommandFilter const& commandFilter) {
501 // First check whether there is at least one enabled command at each module
502 // This avoids evaluating unnecessarily many guards.
503 // If we find one module without an enabled command, we return boost::none.
504 // At the same time, we store pointers to the relevant modules, the relevant command sets and the first enabled command within each set.
505
506 // Iterate over all modules.
507 std::vector<ActiveCommandData> activeCommands;
508 for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
509 storm::prism::Module const& module = program.getModule(i);
510
511 // If the module has no command labeled with the given action, we can skip this module.
512 if (!module.hasActionIndex(actionIndex)) {
513 continue;
514 }
515
516 std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
517
518 // If the module contains the action, but there is no command in the module that is labeled with
519 // this action, we don't have any feasible command combinations.
520 if (commandIndices.empty()) {
521 return boost::none;
522 }
523
524 // Look up commands by their indices and check if the guard evaluates to true in the given state.
525 bool hasOneEnabledCommand = false;
526 for (auto commandIndexIt = commandIndices.begin(), commandIndexIte = commandIndices.end(); commandIndexIt != commandIndexIte; ++commandIndexIt) {
527 storm::prism::Command const& command = module.getCommand(*commandIndexIt);
528 if (!isCommandPotentiallySynchronizing(command)) {
529 continue;
530 }
531 if (commandFilter != CommandFilter::All) {
532 STORM_LOG_ASSERT(commandFilter == CommandFilter::Markovian || commandFilter == CommandFilter::Probabilistic, "Unexpected command filter.");
533 if ((commandFilter == CommandFilter::Markovian) != command.isMarkovian()) {
534 continue;
535 }
536 }
537 if (this->evaluator->asBool(command.getGuardExpression())) {
538 // Found the first enabled command for this module.
539 hasOneEnabledCommand = true;
540 activeCommands.emplace_back(&module, &commandIndices, commandIndexIt);
541 break;
542 }
543 }
544
545 if (!hasOneEnabledCommand) {
546 return boost::none;
547 }
548 }
549
550 // If we reach this point, there has to be at least one active command for each relevant module.
551 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> result;
552
553 // Iterate over all command sets.
554 for (auto const& activeCommand : activeCommands) {
555 std::vector<std::reference_wrapper<storm::prism::Command const>> commands;
556
557 auto commandIndexIt = activeCommand.currentCommandIndexIt;
558 // The command at the current position is already known to be enabled
559 commands.push_back(activeCommand.modulePtr->getCommand(*commandIndexIt));
560
561 // Look up commands by their indices and add them if the guard evaluates to true in the given state.
562 auto commandIndexIte = activeCommand.commandIndicesPtr->end();
563 for (++commandIndexIt; commandIndexIt != commandIndexIte; ++commandIndexIt) {
564 storm::prism::Command const& command = activeCommand.modulePtr->getCommand(*commandIndexIt);
565 if (commandFilter != CommandFilter::All) {
566 STORM_LOG_ASSERT(commandFilter == CommandFilter::Markovian || commandFilter == CommandFilter::Probabilistic, "Unexpected command filter.");
567 if ((commandFilter == CommandFilter::Markovian) != command.isMarkovian()) {
568 continue;
569 }
570 }
571 if (this->evaluator->asBool(command.getGuardExpression())) {
572 commands.push_back(command);
573 }
574 }
575
576 result.push_back(std::move(commands));
577 }
578
579 STORM_LOG_ASSERT(!result.empty(), "Expected non-empty list.");
580 return result;
581}
582
583template<typename ValueType, typename BaseValueType>
585 if constexpr (storm::IsIntervalType<ValueType>) {
586 if (update.isLikelihoodInterval()) {
587 BaseValueType lower = evaluator.asRational(update.getLikelihoodExpressionInterval().first);
588 BaseValueType upper = evaluator.asRational(update.getLikelihoodExpressionInterval().second);
589 return ValueType(lower, carl::BoundType::WEAK, upper, carl::BoundType::WEAK);
590 } else {
591 return evaluator.asRational(update.getLikelihoodExpression());
592 }
593 } else {
594 // We don't expect to see an interval likelihood now. This case should have been catched earlier.
595 STORM_LOG_ASSERT(!update.isLikelihoodInterval(), "Unexpected interval likelihood for non-interval model in update " << update << ".");
596 return evaluator.asRational(update.getLikelihoodExpression());
597 }
598}
599
600template<typename ValueType, typename StateType>
601std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getAsynchronousChoices(CompressedState const& state,
602 StateToIdCallback stateToIdCallback,
603 CommandFilter const& commandFilter) {
604 std::vector<Choice<ValueType>> result;
605
606 // Iterate over all modules.
607 for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
608 storm::prism::Module const& module = program.getModule(i);
609
610 // Iterate over all commands.
611 for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
612 storm::prism::Command const& command = module.getCommand(j);
613
614 // Only consider commands that are not possibly synchronizing.
615 if (isCommandPotentiallySynchronizing(command))
616 continue;
617
618 if (commandFilter != CommandFilter::All) {
619 STORM_LOG_ASSERT(commandFilter == CommandFilter::Markovian || commandFilter == CommandFilter::Probabilistic, "Unexpected command filter.");
620 if ((commandFilter == CommandFilter::Markovian) != command.isMarkovian()) {
621 continue;
622 }
623 }
624 if (this->actionMask != nullptr) {
625 if (!this->actionMask->query(*this, command.getActionIndex())) {
626 continue;
627 }
628 }
629
630 // Skip the command, if it is not enabled.
631 if (!this->evaluator->asBool(command.getGuardExpression())) {
632 continue;
633 }
634
635 result.push_back(Choice<ValueType>(command.getActionIndex(), command.isMarkovian()));
636 Choice<ValueType>& choice = result.back();
637
638 // Remember the choice origin only if we were asked to.
639 if (this->options.isBuildChoiceOriginsSet()) {
640 CommandSet commandIndex{command.getGlobalIndex()};
641 choice.addOriginData(boost::any(std::move(commandIndex)));
642 }
643
644 // Iterate over all updates of the current command.
645 ValueType probabilitySum = storm::utility::zero<ValueType>();
646 for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) {
647 storm::prism::Update const& update = command.getUpdate(k);
648
649 ValueType probability = evaluateLikelihoodExpression<ValueType>(update, *this->evaluator);
650 if (probability != storm::utility::zero<ValueType>()) {
651 // Obtain target state index and add it to the list of known states. If it has not yet been
652 // seen, we also add it to the set of states that have yet to be explored.
653 StateType stateIndex = stateToIdCallback(applyUpdate(state, update));
654
655 // Update the choice by adding the probability/target state to it.
656 choice.addProbability(stateIndex, probability);
657 if (this->options.isExplorationChecksSet()) {
658 if constexpr (!std::is_same_v<ValueType, storm::RationalFunction>) {
659 STORM_LOG_THROW(probability > storm::utility::zero<ValueType>(), storm::exceptions::WrongFormatException,
660 "Probability expression in update '" << update << " evaluates to negative value " << probability << ".");
661 STORM_LOG_THROW(!program.isDiscreteTimeModel() || probability <= storm::utility::one<ValueType>(),
662 storm::exceptions::WrongFormatException,
663 "Probability expression in update '" << update << " evaluates to value " << probability << " >1.");
664 }
665 probabilitySum += probability;
666 }
667 }
668 }
669
670 // Create the state-action reward for the newly created choice.
671 for (auto const& rewardModel : rewardModels) {
672 ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
673 if (rewardModel.get().hasStateActionRewards()) {
674 for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
675 if (stateActionReward.getActionIndex() == choice.getActionIndex() &&
676 this->evaluator->asBool(stateActionReward.getStatePredicateExpression())) {
677 stateActionRewardValue += ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression()));
678 }
679 }
680 }
681 choice.addReward(stateActionRewardValue);
682 }
683
684 if (this->options.isBuildChoiceLabelsSet() && command.isLabeled()) {
685 choice.addLabel(program.getActionName(command.getActionIndex()));
686 }
687
689 if (command.getActionIndex() == 0) {
690 // Unlabeled command
691 auto const playerOfModule = moduleIndexToPlayerIndexMap.at(i);
692 STORM_LOG_THROW(playerOfModule != storm::storage::INVALID_PLAYER_INDEX, storm::exceptions::WrongFormatException,
693 "Module " << module.getName() << " is not owned by any player but has at least one enabled, unlabeled command.");
694 choice.setPlayerIndex(playerOfModule);
695 } else {
696 // Labelled command (that happens to not synchronize with another command
697 auto const playerOfAction = actionIndexToPlayerIndexMap.at(command.getActionIndex());
698 STORM_LOG_THROW(playerOfAction != storm::storage::INVALID_PLAYER_INDEX, storm::exceptions::WrongFormatException,
699 "Command with action label '" << program.getActionName(command.getActionIndex()) << "' is not owned by any player.");
700 choice.setPlayerIndex(playerOfAction);
701 }
702 }
703
704 if (this->options.isExplorationChecksSet()) {
705 // Check that the resulting distribution is in fact a distribution.
706 STORM_LOG_THROW(!program.isDiscreteTimeModel() || !storm::utility::isConstant(probabilitySum) || this->comparator.isOne(probabilitySum),
707 storm::exceptions::WrongFormatException,
708 "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ").");
709 }
710 }
711 }
712
713 return result;
714}
715
716template<typename ValueType, typename StateType>
717std::vector<Choice<ValueType>> PrismNextStateGenerator<ValueType, StateType>::getSelfLoopsForAllActions(CompressedState const& state,
718 StateToIdCallback stateToIdCallback,
719 CommandFilter const& commandFilter) {
720 std::vector<Choice<ValueType>> result;
721
722 // Asynchronous actions
723 // Iterate over all modules.
724 for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) {
725 storm::prism::Module const& module = program.getModule(i);
726
727 // Iterate over all commands.
728 for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) {
729 storm::prism::Command const& command = module.getCommand(j);
730
731 // Only consider commands that are not possibly synchronizing.
732 if (isCommandPotentiallySynchronizing(command))
733 continue;
734
735 if (this->actionMask != nullptr) {
736 if (!this->actionMask->query(*this, command.getActionIndex())) {
737 continue;
738 }
739 }
740
741 // Skip the command, if it is not enabled.
742 if (!this->evaluator->asBool(command.getGuardExpression())) {
743 continue;
744 }
745
746 result.push_back(Choice<ValueType>(command.getActionIndex(), command.isMarkovian()));
747 Choice<ValueType>& choice = result.back();
748
749 // Remember the choice origin only if we were asked to.
750 if (this->options.isBuildChoiceOriginsSet()) {
751 CommandSet commandIndex{command.getGlobalIndex()};
752 choice.addOriginData(boost::any(std::move(commandIndex)));
753 }
754 choice.addProbability(stateToIdCallback(*this->state), storm::utility::one<ValueType>());
755
756 // Create the state-action reward for the newly created choice.
757 for (auto const& rewardModel : rewardModels) {
758 ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
759 if (rewardModel.get().hasStateActionRewards()) {
760 for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
761 if (stateActionReward.getActionIndex() == choice.getActionIndex() &&
762 this->evaluator->asBool(stateActionReward.getStatePredicateExpression())) {
763 stateActionRewardValue += ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression()));
764 }
765 }
766 }
767 choice.addReward(stateActionRewardValue);
768 }
769
770 if (this->options.isBuildChoiceLabelsSet() && command.isLabeled()) {
771 choice.addLabel(program.getActionName(command.getActionIndex()));
772 }
773 }
774 }
775
776 // Synchronizing actions
777 for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) {
778 if (this->actionMask != nullptr) {
779 if (!this->actionMask->query(*this, actionIndex)) {
780 continue;
781 }
782 }
783 boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists =
784 getActiveCommandsByActionIndex(actionIndex, commandFilter);
785
786 // Only process this action label, if there is at least one feasible solution.
787 if (optionalActiveCommandLists) {
788 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get();
789 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size());
790
791 // Initialize the list of iterators.
792 for (size_t i = 0; i < activeCommandList.size(); ++i) {
793 iteratorList[i] = activeCommandList[i].cbegin();
794 }
795
796 // As long as there is one feasible combination of commands, keep on expanding it.
797 bool done = false;
798 while (!done) {
799 // At this point, we applied all commands of the current command combination and newTargetStates
800 // contains all target states and their respective probabilities. That means we are now ready to
801 // add the choice to the list of transitions.
802 result.push_back(Choice<ValueType>(actionIndex));
803
804 // Now create the actual distribution.
805 Choice<ValueType>& choice = result.back();
806
807 // Remember the choice label and origins only if we were asked to.
808 if (this->options.isBuildChoiceLabelsSet()) {
809 choice.addLabel(program.getActionName(actionIndex));
810 }
811 if (this->options.isBuildChoiceOriginsSet()) {
812 CommandSet commandIndices;
813 for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
814 commandIndices.insert(iteratorList[i]->get().getGlobalIndex());
815 }
816 choice.addOriginData(boost::any(std::move(commandIndices)));
817 }
818 choice.addProbability(stateToIdCallback(*this->state), storm::utility::one<ValueType>());
819
820 // Create the state-action reward for the newly created choice.
821 for (auto const& rewardModel : rewardModels) {
822 ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
823 if (rewardModel.get().hasStateActionRewards()) {
824 for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
825 if (stateActionReward.getActionIndex() == choice.getActionIndex() &&
826 this->evaluator->asBool(stateActionReward.getStatePredicateExpression())) {
827 stateActionRewardValue += ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression()));
828 }
829 }
830 }
831 choice.addReward(stateActionRewardValue);
832 }
833
834 // Now, check whether there is one more command combination to consider.
835 bool movedIterator = false;
836 for (int_fast64_t j = iteratorList.size() - 1; !movedIterator && j >= 0; --j) {
837 ++iteratorList[j];
838 if (iteratorList[j] != activeCommandList[j].end()) {
839 movedIterator = true;
840 } else {
841 // Reset the iterator to the beginning of the list.
842 iteratorList[j] = activeCommandList[j].begin();
843 }
844 }
845
846 done = !movedIterator;
847 }
848 }
849 }
850
851 return result;
852}
853
854template<typename ValueType, typename StateType>
855void PrismNextStateGenerator<ValueType, StateType>::generateSynchronizedDistribution(
856 storm::storage::BitVector const& state, ValueType const& probability, uint64_t position,
857 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> const& iteratorList,
858 storm::generator::Distribution<StateType, ValueType>& distribution, StateToIdCallback stateToIdCallback) {
859 if (storm::utility::isZero<ValueType>(probability)) {
860 return;
861 }
862
863 if (position >= iteratorList.size()) {
864 StateType id = stateToIdCallback(state);
865 distribution.add(id, std::move(probability));
866 } else {
867 storm::prism::Command const& command = *iteratorList[position];
868 for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) {
869 storm::prism::Update const& update = command.getUpdate(j);
870 ValueType updateProbability = evaluateLikelihoodExpression<ValueType>(update, *this->evaluator);
871 if constexpr (!std::is_same_v<ValueType, storm::RationalFunction>) {
872 if (this->options.isExplorationChecksSet()) {
873 STORM_LOG_THROW(updateProbability >= storm::utility::zero<ValueType>(), storm::exceptions::WrongFormatException,
874 "Probability expression in update '" << update << " evaluates to negative value " << updateProbability << ".");
875 STORM_LOG_THROW(!program.isDiscreteTimeModel() || updateProbability <= storm::utility::one<ValueType>(),
876 storm::exceptions::WrongFormatException,
877 "Probability expression in update '" << update << " evaluates to value " << updateProbability << " >1.");
878 }
879 }
880 updateProbability *= probability;
881 generateSynchronizedDistribution(applyUpdate(state, update), updateProbability, position + 1, iteratorList, distribution, stateToIdCallback);
882 }
883 }
884}
885
886template<typename ValueType, typename StateType>
887void PrismNextStateGenerator<ValueType, StateType>::addSynchronousChoices(std::vector<Choice<ValueType>>& choices, CompressedState const& state,
888 StateToIdCallback stateToIdCallback, CommandFilter const& commandFilter) {
889 for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) {
890 if (this->actionMask != nullptr) {
891 if (!this->actionMask->query(*this, actionIndex)) {
892 continue;
893 }
894 }
895 boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists =
896 getActiveCommandsByActionIndex(actionIndex, commandFilter);
897
898 // Only process this action label, if there is at least one feasible solution.
899 if (optionalActiveCommandLists) {
900 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get();
901 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size());
902
903 // Initialize the list of iterators.
904 for (size_t i = 0; i < activeCommandList.size(); ++i) {
905 iteratorList[i] = activeCommandList[i].cbegin();
906 }
907
909
910 // As long as there is one feasible combination of commands, keep on expanding it.
911 bool done = false;
912 while (!done) {
913 distribution.clear();
914 generateSynchronizedDistribution(state, storm::utility::one<ValueType>(), 0, iteratorList, distribution, stateToIdCallback);
915 distribution.compress();
916
917 // At this point, we applied all commands of the current command combination and newTargetStates
918 // contains all target states and their respective probabilities. That means we are now ready to
919 // add the choice to the list of transitions.
920 choices.push_back(Choice<ValueType>(actionIndex));
921
922 // Now create the actual distribution.
923 Choice<ValueType>& choice = choices.back();
924
926 storm::storage::PlayerIndex const& playerOfAction = actionIndexToPlayerIndexMap.at(actionIndex);
927 STORM_LOG_THROW(playerOfAction != storm::storage::INVALID_PLAYER_INDEX, storm::exceptions::WrongFormatException,
928 "Action " << program.getActionName(actionIndex)
929 << " is not owned by any player but has at least one enabled, unlabeled (synchronized) command.");
930 choice.setPlayerIndex(playerOfAction);
931 }
932
933 // Remember the choice label and origins only if we were asked to.
934 if (this->options.isBuildChoiceLabelsSet()) {
935 choice.addLabel(program.getActionName(actionIndex));
936 }
937 if (this->options.isBuildChoiceOriginsSet()) {
938 CommandSet commandIndices;
939 for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) {
940 commandIndices.insert(iteratorList[i]->get().getGlobalIndex());
941 }
942 choice.addOriginData(boost::any(std::move(commandIndices)));
943 }
944
945 // Add the probabilities/rates to the newly created choice.
946 ValueType probabilitySum = storm::utility::zero<ValueType>();
947 choice.reserve(std::distance(distribution.begin(), distribution.end()));
948 for (auto const& stateProbability : distribution) {
949 choice.addProbability(stateProbability.getState(), stateProbability.getValue());
950 if (this->options.isExplorationChecksSet()) {
951 probabilitySum += stateProbability.getValue();
952 }
953 }
954
955 if (this->options.isExplorationChecksSet()) {
956 // Check that the resulting distribution is in fact a distribution.
957 STORM_LOG_THROW(!program.isDiscreteTimeModel() || !storm::utility::isConstant(probabilitySum) || this->comparator.isOne(probabilitySum),
958 storm::exceptions::WrongFormatException,
959 "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ").");
960 }
961
962 // Create the state-action reward for the newly created choice.
963 for (auto const& rewardModel : rewardModels) {
964 ValueType stateActionRewardValue = storm::utility::zero<ValueType>();
965 if (rewardModel.get().hasStateActionRewards()) {
966 for (auto const& stateActionReward : rewardModel.get().getStateActionRewards()) {
967 if (stateActionReward.getActionIndex() == choice.getActionIndex() &&
968 this->evaluator->asBool(stateActionReward.getStatePredicateExpression())) {
969 stateActionRewardValue += ValueType(this->evaluator->asRational(stateActionReward.getRewardValueExpression()));
970 }
971 }
972 }
973 choice.addReward(stateActionRewardValue);
974 }
975
976 // Now, check whether there is one more command combination to consider.
977 bool movedIterator = false;
978 for (int_fast64_t j = iteratorList.size() - 1; !movedIterator && j >= 0; --j) {
979 ++iteratorList[j];
980 if (iteratorList[j] != activeCommandList[j].end()) {
981 movedIterator = true;
982 } else {
983 // Reset the iterator to the beginning of the list.
984 iteratorList[j] = activeCommandList[j].begin();
985 }
986 }
987
988 done = !movedIterator;
989 }
990 }
991 }
992}
993
994template<typename ValueType, typename StateType>
995std::map<std::string, storm::storage::PlayerIndex> PrismNextStateGenerator<ValueType, StateType>::getPlayerNameToIndexMap() const {
996 return program.getPlayerNameToIndexMapping();
997}
998
999template<typename ValueType, typename StateType>
1001 std::vector<StateType> const& initialStateIndices,
1002 std::vector<StateType> const& deadlockStateIndices,
1003 std::vector<StateType> const& unexploredStateIndices) {
1004 // Gather a vector of labels and their expressions.
1005 std::vector<std::pair<std::string, storm::expressions::Expression>> labels;
1006 if (this->options.isBuildAllLabelsSet()) {
1007 for (auto const& label : program.getLabels()) {
1008 labels.push_back(std::make_pair(label.getName(), label.getStatePredicateExpression()));
1009 }
1010 } else {
1011 for (auto const& labelName : this->options.getLabelNames()) {
1012 if (program.hasLabel(labelName)) {
1013 labels.push_back(std::make_pair(labelName, program.getLabelExpression(labelName)));
1014 } else {
1015 STORM_LOG_THROW(this->isSpecialLabel(labelName), storm::exceptions::InvalidArgumentException,
1016 "Cannot build labeling for unknown label '" << labelName << "'.");
1017 }
1018 }
1019 }
1020
1021 return NextStateGenerator<ValueType, StateType>::label(stateStorage, initialStateIndices, deadlockStateIndices, unexploredStateIndices, labels);
1022}
1023
1024template<typename ValueType, typename StateType>
1026 // TODO consider to avoid reloading by computing these bitvectors in an earlier build stage
1028
1029 if (program.getNumberOfObservationLabels() == 0) {
1030 return result;
1031 }
1032 unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator);
1033 for (uint64_t i = 0; i < program.getNumberOfObservationLabels(); ++i) {
1034 result.setFromInt(64 * i, 64, this->evaluator->asInt(program.getObservationLabels()[i].getStatePredicateExpression()));
1035 }
1036 return result;
1037}
1038
1039template<typename ValueType, typename StateType>
1040void PrismNextStateGenerator<ValueType, StateType>::extendStateInformation(storm::json<BaseValueType>& result) const {
1041 for (uint64_t i = 0; i < program.getNumberOfObservationLabels(); ++i) {
1042 result[program.getObservationLabels()[i].getName()] = this->evaluator->asInt(program.getObservationLabels()[i].getStatePredicateExpression());
1043 }
1044}
1045
1046template<typename ValueType, typename StateType>
1048 return rewardModels.size();
1049}
1050
1051template<typename ValueType, typename StateType>
1053 storm::prism::RewardModel const& rewardModel = rewardModels[index].get();
1054 return storm::builder::RewardModelInformation(rewardModel.getName(), rewardModel.hasStateRewards(), rewardModel.hasStateActionRewards(),
1055 rewardModel.hasTransitionRewards());
1056}
1057
1058template<typename ValueType, typename StateType>
1059std::shared_ptr<storm::storage::sparse::ChoiceOrigins> PrismNextStateGenerator<ValueType, StateType>::generateChoiceOrigins(
1060 std::vector<boost::any>& dataForChoiceOrigins) const {
1061 if (!this->getOptions().isBuildChoiceOriginsSet()) {
1062 return nullptr;
1063 }
1064
1065 std::vector<uint_fast64_t> identifiers;
1066 identifiers.reserve(dataForChoiceOrigins.size());
1067
1068 std::map<CommandSet, uint_fast64_t> commandSetToIdentifierMap;
1069 // The empty commandset (i.e., the choices without origin) always has to get identifier getIdentifierForChoicesWithNoOrigin() -- which is assumed to be 0
1070 STORM_LOG_ASSERT(storm::storage::sparse::ChoiceOrigins::getIdentifierForChoicesWithNoOrigin() == 0, "The no origin identifier is assumed to be zero");
1071 commandSetToIdentifierMap.insert(std::make_pair(CommandSet(), 0));
1072 uint_fast64_t currentIdentifier = 1;
1073 for (boost::any& originData : dataForChoiceOrigins) {
1074 STORM_LOG_ASSERT(originData.empty() || boost::any_cast<CommandSet>(&originData) != nullptr,
1075 "Origin data has unexpected type: " << originData.type().name() << ".");
1076
1077 CommandSet currentCommandSet = originData.empty() ? CommandSet() : boost::any_cast<CommandSet>(std::move(originData));
1078 auto insertionRes = commandSetToIdentifierMap.insert(std::make_pair(std::move(currentCommandSet), currentIdentifier));
1079 identifiers.push_back(insertionRes.first->second);
1080 if (insertionRes.second) {
1081 ++currentIdentifier;
1082 }
1083 }
1084
1085 std::vector<CommandSet> identifierToCommandSetMapping(currentIdentifier);
1086 for (auto const& setIdPair : commandSetToIdentifierMap) {
1087 identifierToCommandSetMapping[setIdPair.second] = setIdPair.first;
1088 }
1089
1090 return std::make_shared<storm::storage::sparse::PrismChoiceOrigins>(std::make_shared<storm::prism::Program>(program), std::move(identifiers),
1091 std::move(identifierToCommandSetMapping));
1092}
1093
1094template<typename ValueType, typename StateType>
1096 return program.getPossiblySynchronizingCommands().get(command.getGlobalIndex());
1097}
1098
1099template class PrismNextStateGenerator<double>;
1100template class PrismNextStateGenerator<storm::RationalNumber>;
1101template class PrismNextStateGenerator<storm::RationalFunction>;
1102template class PrismNextStateGenerator<storm::Interval>;
1103} // namespace generator
1104} // namespace storm
uint64_t getReservedBitsForUnboundedVariables() const
std::set< std::string > const & getLabelNames() const
Which labels are built.
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
bool isTrue() const
Checks if the expression is equal to the boolean literal true.
bool isInitialized() const
Checks whether the object encapsulates a base-expression.
Expression integer(int_fast64_t value) const
Creates an expression that characterizes the given integer literal.
Action masks are arguments you can give to the state generator that limit which states are generated.
void clear()
Clears this distribution.
ContainerType::iterator begin()
Access to iterators over the entries of the distribution.
void compress()
Compresses the internal storage by summing the values of entries which agree on the index.
ContainerType::iterator end()
void add(DistributionEntry< IndexType, ValueType > const &entry)
Adds the given entry to the distribution.
virtual storm::models::sparse::StateLabeling label(storm::storage::sparse::StateStorage< StateType > const &stateStorage, std::vector< StateType > const &initialStateIndices={}, std::vector< StateType > const &deadlockStateIndices={}, std::vector< StateType > const &unexploredStateIndices={})=0
storm::storage::FlatSet< uint_fast64_t > CommandSet
virtual std::vector< StateType > getInitialStates(StateToIdCallback const &stateToIdCallback) override
NextStateGenerator< ValueType, StateType >::StateToIdCallback StateToIdCallback
virtual StateBehavior< ValueType, StateType > expand(StateToIdCallback const &stateToIdCallback) override
virtual ModelType getModelType() const override
virtual storm::models::sparse::StateLabeling label(storm::storage::sparse::StateStorage< StateType > const &stateStorage, std::vector< StateType > const &initialStateIndices={}, std::vector< StateType > const &deadlockStateIndices={}, std::vector< StateType > const &unexploredStateIndices={}) override
PrismNextStateGenerator(storm::prism::Program const &program, NextStateGeneratorOptions const &options=NextStateGeneratorOptions(), std::shared_ptr< ActionMask< ValueType, StateType > > const &=nullptr)
virtual std::size_t getNumberOfRewardModels() const override
virtual std::shared_ptr< storm::storage::sparse::ChoiceOrigins > generateChoiceOrigins(std::vector< boost::any > &dataForChoiceOrigins) const override
static bool canHandle(storm::prism::Program const &program)
A quick check to detect whether the given model is not supported.
bool evaluateBooleanExpressionInCurrentState(storm::expressions::Expression const &) const
virtual std::map< std::string, storm::storage::PlayerIndex > getPlayerNameToIndexMap() const override
virtual storm::builder::RewardModelInformation getRewardModelInformation(uint64_t const &index) const override
void addChoice(Choice< ValueType, StateType > &&choice)
Adds the given choice to the behavior of the state.
void addStateReward(ValueType const &stateReward)
Adds the given state reward to the behavior of the state.
void setExpanded(bool newValue=true)
Sets whether the state was expanded.
This class manages the labeling of the state space with a number of (atomic) labels.
bool isLabeled() const
Retrieves whether the command possesses a synchronization label.
Definition Command.cpp:82
std::size_t getNumberOfUpdates() const
Retrieves the number of updates associated with this command.
Definition Command.cpp:39
storm::prism::Update const & getUpdate(uint_fast64_t index) const
Retrieves a reference to the update with the given index.
Definition Command.cpp:43
storm::expressions::Expression const & getGuardExpression() const
Retrieves a reference to the guard of the command.
Definition Command.cpp:35
uint_fast64_t getActionIndex() const
Retrieves the action index of this command.
Definition Command.cpp:19
bool isMarkovian() const
Retrieves whether the command is a Markovian command, i.e.
Definition Command.cpp:23
uint_fast64_t getGlobalIndex() const
Retrieves the global index of the command, that is, a unique index over all modules.
Definition Command.cpp:56
bool hasIntervalUpdates() const
Retrieves whether the program considers at least one update with an interval probability/rate.
Definition Program.cpp:710
ModelType getModelType() const
Retrieves the model type of the model.
Definition Program.cpp:247
std::vector< storm::expressions::Expression > getAllRangeExpressions() const
Retrieves a list of expressions that characterize the legal ranges of all variables.
Definition Program.cpp:512
std::vector< RewardModel > const & getRewardModels() const
Retrieves the reward models of the program.
Definition Program.cpp:821
RewardModel const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name.
Definition Program.cpp:829
std::vector< std::reference_wrapper< Constant const > > getUndefinedConstants() const
Retrieves the undefined constants in the program.
Definition Program.cpp:368
bool isPartiallyObservable() const
Retrieves whether the model has restricted observability.
Definition Program.cpp:259
std::string const & getActionName(uint_fast64_t actionIndex) const
Retrieves the action name of the given action index.
Definition Program.cpp:755
bool isDiscreteTimeModel() const
Retrieves whether the model is a discrete-time model, i.e.
Definition Program.cpp:251
storm::expressions::Expression const & getLabelExpression(std::string const &label) const
Retrieves the expression associated with the given label, if it exists.
Definition Program.cpp:860
std::vector< ObservationLabel > const & getObservationLabels() const
Retrieves all observation labels that are defined by this program.
Definition Program.cpp:913
std::map< uint_fast64_t, storm::storage::PlayerIndex > buildActionIndexToPlayerIndexMap() const
Retrieves a vector whose i'th entry corresponds to the player controlling action with index i.
Definition Program.cpp:590
bool isDeterministicModel() const
Retrieves whether the model is one without nondeterministic choices, i.e.
Definition Program.cpp:255
bool undefinedConstantsAreGraphPreserving() const
Checks that undefined constants (parameters) of the model preserve the graph of the underlying model.
Definition Program.cpp:294
std::size_t getNumberOfRewardModels() const
Retrieves the number of reward models in the program.
Definition Program.cpp:825
std::size_t getNumberOfObservationLabels() const
Retrieves the number of observation labels in the program.
Definition Program.cpp:917
std::map< std::string, storm::storage::PlayerIndex > const & getPlayerNameToIndexMapping() const
Definition Program.cpp:574
storm::expressions::ExpressionManager & getManager() const
Retrieves the manager responsible for the expressions of this program.
Definition Program.cpp:2378
bool hasLabel(std::string const &labelName) const
Checks whether the program has a label with the given name.
Definition Program.cpp:841
std::vector< storm::storage::PlayerIndex > buildModuleIndexToPlayerIndexMap() const
Retrieves a vector whose i'th entry corresponds to the player controlling module i.
Definition Program.cpp:578
std::string getUndefinedConstantsAsString() const
Retrieves the undefined constants in the program as a comma-separated string.
Definition Program.cpp:378
storm::expressions::Expression getInitialStatesExpression() const
Retrieves an expression characterizing the initial states.
Definition Program.cpp:662
std::size_t getNumberOfModules() const
Retrieves the number of modules in the program.
Definition Program.cpp:611
bool hasInitialConstruct() const
Retrieves whether the program specifies an initial construct.
Definition Program.cpp:645
bool hasUndefinedConstants() const
Retrieves whether there are undefined constants of any type in the program.
Definition Program.cpp:285
bool specifiesSystemComposition() const
Retrieves whether the program specifies a system composition in terms of process algebra operations o...
Definition Program.cpp:723
std::vector< Label > const & getLabels() const
Retrieves all labels that are defined by the probabilitic program.
Definition Program.cpp:846
storm::storage::BitVector const & getPossiblySynchronizingCommands() const
Compute the (labelled) commands in the program that may be synchronizing.
Definition Program.cpp:921
bool hasRewardModel() const
Retrieves whether the program has reward models.
Definition Program.cpp:812
bool hasStateRewards() const
Retrieves whether there are any state rewards.
bool hasTransitionRewards() const
Retrieves whether there are any transition rewards.
std::string const & getName() const
Retrieves the name of the reward model.
bool hasStateActionRewards() const
Retrieves whether there are any state-action rewards.
bool isLikelihoodInterval() const
Definition Update.cpp:57
ExpressionPair const & getLikelihoodExpressionInterval() const
Retrieves the two expression for the interval likelihood of this update.
Definition Update.cpp:66
std::vector< storm::prism::Assignment > const & getAssignments() const
Retrieves a reference to the map of variable names to their respective assignments.
Definition Update.cpp:75
storm::expressions::Expression const & getLikelihoodExpression() const
Retrieves the expression for the likelihood of this update.
Definition Update.cpp:61
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void setFromInt(uint64_t bitIndex, uint64_t numberOfBits, uint64_t value)
Sets the selected number of lowermost bits of the provided value at the given bit index.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
static uint_fast64_t getIdentifierForChoicesWithNoOrigin()
virtual std::unique_ptr< storm::solver::SmtSolver > create(storm::expressions::ExpressionManager &manager) const
Creates a new SMT solver instance.
Definition solver.cpp:124
#define STORM_LOG_DEBUG(message)
Definition logging.h:18
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
void unpackStateIntoEvaluator(CompressedState const &state, VariableInformation const &variableInformation, storm::expressions::ExpressionEvaluator< ValueType > &evaluator)
Unpacks the compressed state into the evaluator.
storm::storage::BitVector CompressedState
ValueType evaluateLikelihoodExpression(storm::prism::Update const &update, storm::expressions::ExpressionEvaluator< BaseValueType > const &evaluator)
PlayerIndex const INVALID_PLAYER_INDEX
Definition PlayerIndex.h:8
uint64_t PlayerIndex
Definition PlayerIndex.h:7
void forEach(std::vector< IteratorType > const &its, std::vector< IteratorType > const &ites, std::function< void(uint64_t, decltype(*std::declval< IteratorType >()))> const &setValueCallback, std::function< bool()> const &newCombinationCallback)
bool isConstant(ValueType const &)
nlohmann::basic_json< std::map, std::vector, std::string, bool, int64_t, uint64_t, ValueType > json
Definition JsonForward.h:10
ActiveCommandData(storm::prism::Module const *modulePtr, std::set< uint_fast64_t > const *commandIndicesPtr, typename std::set< uint_fast64_t >::const_iterator currentCommandIndexIt)
std::set< uint_fast64_t >::const_iterator currentCommandIndexIt
std::set< uint_fast64_t > const * commandIndicesPtr
void addOriginData(boost::any const &data)
Adds the given data that specifies the origin of this choice w.r.t.
Definition Choice.cpp:116
void addLabels(std::set< std::string > const &labels)
Adds the given label set to the labels associated with this choice.
Definition Choice.cpp:82
void addProbability(StateType const &state, ValueType const &value)
Adds the given probability value to the given state in the underlying distribution.
Definition Choice.cpp:158
void addReward(ValueType const &value)
Adds the given value to the reward associated with this choice.
Definition Choice.cpp:164