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