295 : model(model), automata(), actionInformation(actionInformation) {
303 this->model.getSystemComposition().accept(*
this, boost::none);
304 STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException,
305 "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata.");
307 STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidArgumentException,
308 "The symbolic JANI model builder currently does not support transient edge destination assignments.");
311 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
312 "Cannot build symbolic model from JANI model that contains non-transient global unbounded integer variables.");
313 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
314 "Cannot build symbolic model from JANI model that contains global non-transient real variables.");
315 for (
auto const& automaton : this->model.getAutomata()) {
316 STORM_LOG_THROW(!automaton.getVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
317 "Cannot build symbolic model from JANI model that contains non-transient unbounded integer variables in automaton '"
318 << automaton.getName() <<
"'.");
320 !automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
321 "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() <<
"'.");
325 return createVariables(manager);
330 STORM_LOG_THROW(it == automata.end(), storm::exceptions::InvalidArgumentException,
331 "Cannot build symbolic model from JANI model whose system composition refers to the automaton '" << composition.
getAutomatonName()
332 <<
"' multiple times.");
339 subcomposition->accept(*
this, data);
348 for (
auto const& nonSilentActionIndex : actionInformation.getNonSilentActionIndices()) {
349 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
350 result.manager->addMetaVariable(actionInformation.getActionName(nonSilentActionIndex));
351 result.actionVariablesMap[nonSilentActionIndex] = variablePair.first;
352 result.allNondeterminismVariables.insert(variablePair.first);
356 uint64_t numberOfNondeterminismVariables = this->model.getNumberOfAutomata();
357 for (
auto const& automaton : this->model.getAutomata()) {
358 numberOfNondeterminismVariables += automaton.getNumberOfEdges();
360 for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
361 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable(
"nondet" + std::to_string(i));
362 result.localNondeterminismVariables.push_back(variablePair.first);
363 result.allNondeterminismVariables.insert(variablePair.first);
367 result.probabilisticNondeterminismVariable = result.manager->addMetaVariable(
"prob").first;
368 result.probabilisticMarker = result.manager->getEncoding(result.probabilisticNondeterminismVariable, 1);
369 result.allNondeterminismVariables.insert(result.probabilisticNondeterminismVariable);
372 for (
auto const& automatonName : this->automata) {
377 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
379 result.automatonToLocationDdVariableMap[automaton.
getName()] = variablePair;
380 result.rowColumnMetaVariablePairs.push_back(variablePair);
382 result.variableToRowMetaVariableMap->emplace(locationExpressionVariable, variablePair.first);
383 result.variableToColumnMetaVariableMap->emplace(locationExpressionVariable, variablePair.second);
386 result.rowMetaVariables.insert(variablePair.first);
387 result.columnMetaVariables.insert(variablePair.second);
390 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
391 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
396 for (
auto const& variable : this->model.getGlobalVariables()) {
398 if (variable.isTransient()) {
402 createVariable(variable, result);
403 globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
405 result.globalVariableRanges = globalVariableRanges.template toAdd<ValueType>();
408 for (
auto const& automaton : this->model.getAutomata()) {
413 std::pair<storm::expressions::Variable, storm::expressions::Variable>
const& locationVariables =
414 result.automatonToLocationDdVariableMap[automaton.
getName()];
415 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(locationVariables.first, locationVariables.second);
416 identity &= variableIdentity;
417 range &= result.manager->getRange(locationVariables.first);
422 if (variable.isTransient()) {
426 createVariable(variable, result);
427 identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
428 range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
431 result.automatonToIdentityMap[automaton.
getName()] = identity.template toAdd<ValueType>();
432 result.automatonToRangeMap[automaton.
getName()] = (range && globalVariableRanges).
template toAdd<ValueType>();
435 ParameterCreator<Type, ValueType> parameterCreator;
436 parameterCreator.create(model, *result.rowExpressionAdapter);
437 if (std::is_same<ValueType, storm::RationalFunction>::value) {
438 result.parameters = parameterCreator.getParameters();
444 void createVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
445 auto const& type = variable.
getType();
446 if (type.isBasicType() && type.asBasicType().isBooleanType()) {
447 createBooleanVariable(variable, result);
448 }
else if (type.isBoundedType() && type.asBoundedType().isIntegerType()) {
449 createBoundedIntegerVariable(variable, result);
451 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Invalid type of variable in JANI model.");
455 void createBoundedIntegerVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
457 STORM_LOG_THROW(type.hasLowerBound(), storm::exceptions::NotSupportedException,
458 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no lower bound.");
459 STORM_LOG_THROW(type.hasUpperBound(), storm::exceptions::NotSupportedException,
460 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no upper bound.");
461 int_fast64_t low = type.getLowerBound().evaluateAsInt();
462 int_fast64_t high = type.getUpperBound().evaluateAsInt();
464 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
467 STORM_LOG_TRACE(
"Created meta variables for global integer variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
470 result.rowMetaVariables.insert(variablePair.first);
473 result.columnMetaVariables.insert(variablePair.second);
474 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
476 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
477 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
478 result.rowColumnMetaVariablePairs.push_back(variablePair);
479 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
480 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
485 void createBooleanVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
486 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
489 STORM_LOG_TRACE(
"Created meta variables for global boolean variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
492 result.rowMetaVariables.insert(variablePair.first);
495 result.columnMetaVariables.insert(variablePair.second);
496 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
498 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
499 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
501 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
502 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
504 result.rowColumnMetaVariablePairs.push_back(variablePair);
509 std::set<std::string> automata;
680 std::set<storm::expressions::Variable>
const& writtenGlobalVariables)
681 : isMarkovian(isMarkovian),
683 transitions(transitions),
684 transientEdgeAssignments(transientEdgeAssignments),
685 variableToWritingFragment() {
687 for (
auto const& variable : writtenGlobalVariables) {
688 variableToWritingFragment[variable] = guard;
695 : isMarkovian(isMarkovian),
697 transitions(transitions),
698 transientEdgeAssignments(transientEdgeAssignments),
699 variableToWritingFragment(variableToWritingFragment) {
724 std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0),
725 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& variableToWritingFragment = {},
728 transitions(transitions),
729 transientEdgeAssignments(transientEdgeAssignments),
730 localNondeterminismVariables(localNondeterminismVariables),
731 variableToWritingFragment(variableToWritingFragment),
732 illegalFragment(illegalFragment),
733 inputEnabled(false) {
738 return localNondeterminismVariables.first;
742 return localNondeterminismVariables.second;
746 return localNondeterminismVariables;
750 return ActionDd(guard, transitions * factor, transientEdgeAssignments, localNondeterminismVariables, variableToWritingFragment, illegalFragment);
758 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> newTransientEdgeAssignments(this->transientEdgeAssignments);
760 auto it = newTransientEdgeAssignments.find(entry.first);
761 if (it == newTransientEdgeAssignments.end()) {
762 newTransientEdgeAssignments[entry.first] = entry.second;
764 it->second += entry.second;
768 std::pair<uint64_t, uint64_t> newLocalNondeterminismVariables =
773 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> newVariableToWritingFragment(this->variableToWritingFragment);
775 auto it = newVariableToWritingFragment.find(entry.first);
776 if (it == newVariableToWritingFragment.end()) {
777 newVariableToWritingFragment[entry.first] = entry.second;
779 it->second |= entry.second;
786 return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment,
796 transitions *= conditionAdd;
797 for (
auto& t : transientEdgeAssignments) {
798 t.second *= conditionAdd;
800 illegalFragment &= condition;
837 : actionIndex(actionIndex), synchronizationVectorIndex(
boost::none), markovian(markovian) {
842 : actionIndex(actionIndex), synchronizationVectorIndex(synchronizationVectorIndex), markovian(markovian) {
846 ActionIdentification(uint64_t actionIndex, boost::optional<uint64_t> synchronizationVectorIndex,
bool markovian =
false)
847 : actionIndex(actionIndex), synchronizationVectorIndex(synchronizationVectorIndex), markovian(markovian) {
852 this->markovian = markovian;
856 return this->markovian;
861 if (synchronizationVectorIndex) {
882 std::size_t seed = 0;
883 boost::hash_combine(seed, identification.
actionIndex);
887 return identification.
markovian ? ~seed : seed;
896 transientLocationAssignments(transientLocationAssignments),
898 localNondeterminismVariables(
std::make_pair<uint64_t, uint64_t>(0, 0)) {
903 return localNondeterminismVariables.first;
907 localNondeterminismVariables.first = newValue;
911 return localNondeterminismVariables.second;
915 localNondeterminismVariables.second = newValue;
919 setLowestLocalNondeterminismVariable(std::min(localNondeterminismVariables.first, getLowestLocalNondeterminismVariable()));
920 setHighestLocalNondeterminismVariable(std::max(localNondeterminismVariables.second, getHighestLocalNondeterminismVariable()));
924 std::unordered_map<ActionIdentification, ActionDd, ActionIdentificationHash>
actions;
938 bool applyMaximumProgress)
939 :
SystemComposer<Type, ValueType>(model, variables, transientVariables),
940 actionInformation(actionInformation),
941 applyMaximumProgress(applyMaximumProgress) {
949 STORM_LOG_THROW(this->model.hasStandardCompliantComposition(), storm::exceptions::WrongFormatException,
950 "Model builder only supports non-nested parallel compositions.");
951 AutomatonDd globalAutomaton = boost::any_cast<AutomatonDd>(this->model.getSystemComposition().accept(*
this, boost::any()));
952 return buildSystemFromAutomaton(globalAutomaton);
956 ActionInstantiation(uint64_t actionIndex, uint64_t synchronizationVectorIndex, uint64_t localNondeterminismVariableOffset,
bool markovian =
false)
957 : actionIndex(actionIndex),
958 synchronizationVectorIndex(synchronizationVectorIndex),
959 localNondeterminismVariableOffset(localNondeterminismVariableOffset),
960 markovian(markovian) {
964 ActionInstantiation(uint64_t actionIndex, uint64_t localNondeterminismVariableOffset,
bool markovian =
false)
965 : actionIndex(actionIndex), localNondeterminismVariableOffset(localNondeterminismVariableOffset), markovian(markovian) {
970 this->markovian = markovian;
974 return this->markovian;
980 if (synchronizationVectorIndex) {
1002 std::size_t seed = 0;
1003 boost::hash_combine(seed, instantiation.
actionIndex);
1008 return instantiation.
isMarkovian() ? ~seed : seed;
1021 actionInstantiations[actionIndex].emplace_back(actionIndex, 0, isCtmc);
1029 std::set<uint64_t> inputEnabledActionIndices;
1031 inputEnabledActionIndices.insert(actionInformation.
getActionIndex(actionName));
1034 return buildAutomatonDd(composition.
getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data),
1035 inputEnabledActionIndices, data.empty());
1039 STORM_LOG_ASSERT(data.empty(),
"Expected parallel composition to be on topmost level to be JANI compliant.");
1044 std::vector<AutomatonDd> subautomata;
1049 for (uint64_t subcompositionIndex = 0; subcompositionIndex < composition.
getNumberOfSubcompositions(); ++subcompositionIndex) {
1052 actionInstantiations[silentActionIndex].emplace_back(silentActionIndex, 0, isCtmc);
1058 ++synchronizationVectorIndex) {
1064 if (subcompositionIndex == synchVector.getPositionOfFirstParticipatingAction()) {
1065 uint64_t actionIndex = actionInformation.
getActionIndex(synchVector.getInput(subcompositionIndex));
1066 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, 0, isCtmc);
1068 uint64_t actionIndex = actionInformation.
getActionIndex(synchVector.getInput(subcompositionIndex));
1073 boost::optional<uint64_t> previousActionPosition = synchVector.getPositionOfPrecedingParticipatingAction(subcompositionIndex);
1074 STORM_LOG_ASSERT(previousActionPosition,
"Inconsistent information about synchronization vector.");
1075 AutomatonDd const& previousAutomatonDd = subautomata[previousActionPosition.get()];
1076 auto precedingActionIndex = actionInformation.
getActionIndex(synchVector.getInput(previousActionPosition.get()));
1077 auto precedingActionIt = previousAutomatonDd.
actions.find(
ActionIdentification(precedingActionIndex, synchronizationVectorIndex, isCtmc));
1079 uint64_t highestLocalNondeterminismVariable = 0;
1080 if (precedingActionIt != previousAutomatonDd.
actions.end()) {
1081 highestLocalNondeterminismVariable = precedingActionIt->second.getHighestLocalNondeterminismVariable();
1084 <<
" that is mentioned in parallel composition.");
1086 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, highestLocalNondeterminismVariable, isCtmc);
1090 subautomata.push_back(boost::any_cast<AutomatonDd>(composition.
getSubcomposition(subcompositionIndex).
accept(*
this, actionInstantiations)));
1097 AutomatonDd composeInParallel(std::vector<AutomatonDd>
const& subautomata, std::vector<storm::jani::SynchronizationVector>
const& synchronizationVectors) {
1098 AutomatonDd result(this->variables.manager->template getAddOne<ValueType>());
1104 std::unordered_map<ActionIdentification, std::vector<ActionDd>, ActionIdentificationHash> actions;
1105 for (uint64_t synchronizationVectorIndex = 0; synchronizationVectorIndex < synchronizationVectors.size(); ++synchronizationVectorIndex) {
1106 auto const& synchVector = synchronizationVectors[synchronizationVectorIndex];
1108 boost::optional<ActionDd> synchronizingAction = combineSynchronizingActions(subautomata, synchVector, synchronizationVectorIndex);
1109 if (synchronizingAction) {
1110 if (applyMaximumProgress) {
1112 "Maximum progress assumption enabled for unexpected model type.");
1114 nonMarkovianActionGuards |= synchronizingAction->guard;
1116 actions[ActionIdentification(actionInformation.
getActionIndex(synchVector.getOutput()),
1118 .emplace_back(synchronizingAction.get());
1127 std::vector<ActionDd> silentActionDds;
1128 std::vector<ActionDd> silentMarkovianActionDds;
1129 for (
auto const& automaton : subautomata) {
1130 for (
auto& actionDd : silentActionDds) {
1131 STORM_LOG_TRACE(
"Extending previous (non-Markovian) silent action by identity of current automaton.");
1132 actionDd = actionDd.multiplyTransitions(automaton.identity);
1134 for (
auto& actionDd : silentMarkovianActionDds) {
1135 STORM_LOG_TRACE(
"Extending previous (Markovian) silent action by identity of current automaton.");
1136 actionDd = actionDd.multiplyTransitions(automaton.identity);
1139 auto silentActionIt = automaton.actions.find(silentActionIdentification);
1140 if (silentActionIt != automaton.actions.end()) {
1141 STORM_LOG_TRACE(
"Extending (non-Markovian) silent action by running identity.");
1142 silentActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1145 silentActionIt = automaton.actions.find(silentMarkovianActionIdentification);
1146 if (silentActionIt != automaton.actions.end()) {
1147 STORM_LOG_TRACE(
"Extending (Markovian) silent action by running identity.");
1148 silentMarkovianActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1151 result.identity *= automaton.identity;
1154 addToTransientAssignmentMap(result.transientLocationAssignments, automaton.transientLocationAssignments);
1157 if (!silentActionDds.empty()) {
1158 auto& allSilentActionDds = actions[silentActionIdentification];
1159 allSilentActionDds.insert(allSilentActionDds.end(), silentActionDds.begin(), silentActionDds.end());
1163 if (applyMaximumProgress) {
1164 auto allSilentActionDdsIt = actions.find(silentActionIdentification);
1165 if (allSilentActionDdsIt != actions.end()) {
1166 for (ActionDd
const& silentActionDd : allSilentActionDdsIt->second) {
1167 nonMarkovianActionGuards |= silentActionDd.guard;
1172 if (!silentMarkovianActionDds.empty()) {
1173 auto& allMarkovianSilentActionDds = actions[silentMarkovianActionIdentification];
1174 allMarkovianSilentActionDds.insert(allMarkovianSilentActionDds.end(), silentMarkovianActionDds.begin(), silentMarkovianActionDds.end());
1175 if (applyMaximumProgress && !nonMarkovianActionGuards.
isZero()) {
1176 auto invertedNonMarkovianGuards = !nonMarkovianActionGuards;
1177 for (ActionDd& markovianActionDd : allMarkovianSilentActionDds) {
1178 markovianActionDd.conjunctGuardWith(invertedNonMarkovianGuards);
1184 for (
auto const& actionDds : actions) {
1185 ActionDd combinedAction;
1186 if (actionDds.first == silentMarkovianActionIdentification) {
1188 combinedAction = actionDds.second.front();
1189 for (uint64_t i = 1;
i < actionDds.second.size(); ++
i) {
1190 combinedAction = combinedAction.add(actionDds.second[i]);
1193 combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front();
1195 result.actions[actionDds.first] = combinedAction;
1196 result.extendLocalNondeterminismVariables(combinedAction.getLocalNondeterminismVariables());
1200 for (
auto const& subautomaton : subautomata) {
1201 result.identity *= subautomaton.identity;
1207 boost::optional<ActionDd> combineSynchronizingActions(std::vector<AutomatonDd>
const& subautomata,
1209 uint64_t synchronizationVectorIndex) {
1210 std::vector<std::pair<uint64_t, std::reference_wrapper<ActionDd const>>> actions;
1212 for (uint64_t subautomatonIndex = 0; subautomatonIndex < subautomata.size(); ++subautomatonIndex) {
1213 auto const& subautomaton = subautomata[subautomatonIndex];
1216 subautomaton.actions.find(ActionIdentification(actionInformation.
getActionIndex(synchronizationVector.
getInput(subautomatonIndex)),
1218 if (it != subautomaton.actions.end()) {
1219 actions.emplace_back(subautomatonIndex, it->second);
1224 nonSynchronizingIdentity *= subautomaton.identity;
1229 bool allActionsInputEnabled =
true;
1230 for (
auto const& action : actions) {
1231 if (!action.second.get().isInputEnabled()) {
1232 allActionsInputEnabled =
false;
1236 boost::optional<storm::dd::Bdd<Type>> guardDisjunction;
1237 if (allActionsInputEnabled) {
1238 guardDisjunction = this->variables.manager->getBddZero();
1244 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1245 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragmentWithoutNondeterminism;
1250 uint64_t lowestNondeterminismVariable = actions.front().second.get().getLowestLocalNondeterminismVariable();
1251 uint64_t highestNondeterminismVariable = actions.front().second.get().getHighestLocalNondeterminismVariable();
1253 bool hasTransientEdgeAssignments =
false;
1254 for (
auto const& actionIndexPair : actions) {
1255 auto const& action = actionIndexPair.second.get();
1256 if (!action.transientEdgeAssignments.empty()) {
1257 hasTransientEdgeAssignments =
true;
1262 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1263 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1266 exitRates = this->variables.manager->template getAddOne<ValueType>();
1267 for (
auto const& actionIndexPair : actions) {
1268 auto const& action = actionIndexPair.second.get();
1270 std::set<storm::expressions::Variable> columnVariablesToAbstract;
1271 std::set_intersection(action.transitions.getContainedMetaVariables().begin(), action.transitions.getContainedMetaVariables().end(),
1272 this->variables.columnMetaVariables.begin(), this->variables.columnMetaVariables.end(),
1273 std::inserter(columnVariablesToAbstract, columnVariablesToAbstract.begin()));
1274 auto actionExitRates = action.transitions.sumAbstract(columnVariablesToAbstract);
1275 exitRates = exitRates.get() * actionExitRates;
1277 if (!action.transientEdgeAssignments.empty()) {
1278 for (
auto const& entry : action.transientEdgeAssignments) {
1279 auto transientEdgeAssignmentIt = transientEdgeAssignments.find(entry.first);
1280 if (transientEdgeAssignmentIt != transientEdgeAssignments.end()) {
1281 transientEdgeAssignmentIt->second *= entry.second / actionExitRates;
1283 transientEdgeAssignments.emplace(entry.first, entry.second / actionExitRates);
1288 }
else if (hasTransientEdgeAssignments) {
1290 for (
auto const& actionIndexPair : actions) {
1291 auto const& action = actionIndexPair.second.get();
1292 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments);
1297 for (
auto const& actionIndexPair : actions) {
1298 auto componentIndex = actionIndexPair.first;
1299 auto const& action = actionIndexPair.second.get();
1301 if (guardDisjunction) {
1302 guardDisjunction.get() |= action.guard;
1305 lowestNondeterminismVariable = std::min(lowestNondeterminismVariable, action.getLowestLocalNondeterminismVariable());
1306 highestNondeterminismVariable = std::max(highestNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1308 if (action.isInputEnabled()) {
1310 transitions *= action.guard.ite(
1312 encodeIndex(0, action.getLowestLocalNondeterminismVariable(),
1313 action.getHighestLocalNondeterminismVariable() - action.getLowestLocalNondeterminismVariable(), this->variables) *
1314 subautomata[componentIndex].identity);
1316 transitions *= action.transitions;
1320 auto nondetVariables =
1321 std::set<storm::expressions::Variable>(this->variables.localNondeterminismVariables.begin() + action.getLowestLocalNondeterminismVariable(),
1322 this->variables.localNondeterminismVariables.begin() + action.getHighestLocalNondeterminismVariable());
1324 for (
auto const& entry : action.variableToWritingFragment) {
1329 auto globalFragmentIt = globalVariableToWritingFragment.find(entry.first);
1330 if (globalFragmentIt != globalVariableToWritingFragment.end()) {
1333 globalFragmentIt->second &= guardedWritingFragment;
1335 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] && guardedWritingFragment.
existsAbstract(nondetVariables);
1336 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] |= guardedWritingFragment.
existsAbstract(nondetVariables);
1340 globalVariableToWritingFragment[entry.first] = guardedWritingFragment;
1341 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] = guardedWritingFragment.
existsAbstract(nondetVariables);
1346 illegalFragment |= action.illegalFragment;
1351 for (
auto& entry : globalVariableToWritingFragment) {
1352 if (action.variableToWritingFragment.find(entry.first) == action.variableToWritingFragment.end() && !action.isInputEnabled()) {
1353 entry.second &= action.guard;
1357 if (!action.isInputEnabled()) {
1358 inputEnabledGuard &= action.guard;
1364 if (allActionsInputEnabled) {
1365 inputEnabledGuard &= guardDisjunction.get();
1366 transitions *= guardDisjunction.get().template toAdd<ValueType>();
1371 illegalFragment &= inputEnabledGuard;
1374 if (hasTransientEdgeAssignments) {
1375 transientEdgeAssignmentWeights = inputEnabledGuard.template toAdd<ValueType>();
1377 transientEdgeAssignmentWeights *= exitRates.get();
1380 for (
auto& entry : transientEdgeAssignments) {
1381 entry.second *= transientEdgeAssignmentWeights;
1385 return ActionDd(inputEnabledGuard, transitions * nonSynchronizingIdentity, transientEdgeAssignments,
1386 std::make_pair(lowestNondeterminismVariable, highestNondeterminismVariable), globalVariableToWritingFragment, illegalFragment);
1392 STORM_LOG_TRACE(
"Multiplying identities to combine unsynchronized actions.");
1393 action1.transitions = action1.transitions * identity2;
1394 action2.transitions = action2.transitions * identity1;
1397 return combineUnsynchronizedActions(action1, action2);
1400 ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2) {
1401 return combineUnsynchronizedActions({action1, action2});
1404 ActionDd combineUnsynchronizedActions(std::vector<ActionDd> actions) {
1408 auto actionIt = actions.begin();
1409 ActionDd result(*actionIt);
1411 for (++actionIt; actionIt != actions.end(); ++actionIt) {
1412 result = ActionDd(result.guard || actionIt->guard, result.transitions + actionIt->transitions,
1413 joinTransientAssignmentMaps(result.transientEdgeAssignments, actionIt->transientEdgeAssignments),
1414 std::make_pair<uint64_t, uint64_t>(0, 0),
1415 joinVariableWritingFragmentMaps(result.variableToWritingFragment, actionIt->variableToWritingFragment),
1416 result.illegalFragment || actionIt->illegalFragment);
1422 uint_fast64_t lowestLocalNondeterminismVariable = actions.front().getLowestLocalNondeterminismVariable();
1423 uint_fast64_t highestLocalNondeterminismVariable = actions.front().getHighestLocalNondeterminismVariable();
1424 for (
auto const& action : actions) {
1425 STORM_LOG_ASSERT(action.getLowestLocalNondeterminismVariable() == lowestLocalNondeterminismVariable,
1426 "Mismatching lowest nondeterminism variable indices.");
1427 highestLocalNondeterminismVariable = std::max(highestLocalNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1431 for (
auto& action : actions) {
1433 for (uint_fast64_t i = action.getHighestLocalNondeterminismVariable();
i < highestLocalNondeterminismVariable; ++
i) {
1434 nondeterminismEncodingBdd &= this->variables.manager->
getEncoding(this->variables.localNondeterminismVariables[i], 0);
1438 action.transitions *= nondeterminismEncoding;
1440 for (
auto& variableFragment : action.variableToWritingFragment) {
1441 variableFragment.second &= nondeterminismEncodingBdd;
1443 for (
auto& transientAssignment : action.transientEdgeAssignments) {
1444 transientAssignment.second *= nondeterminismEncoding;
1448 uint64_t numberOfLocalNondeterminismVariables =
static_cast<uint64_t
>(std::ceil(std::log2(actions.size())));
1451 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1452 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1455 for (uint64_t actionIndex = 0; actionIndex < actions.size(); ++actionIndex) {
1456 ActionDd& action = actions[actionIndex];
1458 guard |= action.guard;
1461 encodeIndex(actionIndex, highestLocalNondeterminismVariable, numberOfLocalNondeterminismVariables, this->variables);
1462 transitions += nondeterminismEncoding * action.transitions;
1464 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments, nondeterminismEncoding);
1467 for (
auto& entry : action.variableToWritingFragment) {
1468 entry.second &= nondeterminismEncodingBdd;
1470 addToVariableWritingFragmentMap(variableToWritingFragment, action.variableToWritingFragment);
1471 illegalFragment |= action.illegalFragment;
1474 return ActionDd(guard, transitions, transientEdgeAssignments,
1475 std::make_pair(lowestLocalNondeterminismVariable, highestLocalNondeterminismVariable + numberOfLocalNondeterminismVariables),
1476 variableToWritingFragment, illegalFragment);
1478 STORM_LOG_THROW(
false, storm::exceptions::InvalidStateException,
"Illegal model type.");
1484 auto transientVariableIt = this->transientVariables.begin();
1485 auto transientVariableIte = this->transientVariables.end();
1486 for (
auto const& assignment : transientAssignments) {
1487 while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) {
1488 ++transientVariableIt;
1490 if (transientVariableIt == transientVariableIte) {
1493 if (*transientVariableIt == assignment.getExpressionVariable()) {
1494 callback(assignment);
1495 ++transientVariableIt;
1509 if (!rangedGuard.
isZero()) {
1511 std::vector<EdgeDestinationDd<Type, ValueType>> destinationDds;
1515 STORM_LOG_WARN_COND(!destinationDds.back().transitions.isZero(),
"Destination does not have any effect.");
1521 guard = sourceLocationBdd && rangedGuard;
1524 std::set<storm::expressions::Variable> globalVariablesInSomeDestination;
1530 for (
auto const& edgeDestinationDd : destinationDds) {
1531 globalVariablesInSomeDestination.insert(edgeDestinationDd.writtenGlobalVariables.begin(), edgeDestinationDd.writtenGlobalVariables.end());
1534 globalVariablesInSomeDestination = this->variables.allGlobalVariables;
1538 for (
auto& destinationDd : destinationDds) {
1539 std::set<storm::expressions::Variable> missingIdentities;
1540 std::set_difference(globalVariablesInSomeDestination.begin(), globalVariablesInSomeDestination.end(),
1541 destinationDd.writtenGlobalVariables.begin(), destinationDd.writtenGlobalVariables.end(),
1542 std::inserter(missingIdentities, missingIdentities.begin()));
1544 for (
auto const& variable : missingIdentities) {
1546 destinationDd.transitions *= this->variables.variableToIdentityMap.at(variable);
1552 for (
auto const& destinationDd : destinationDds) {
1553 transitions += destinationDd.transitions;
1558 transitions *= guardAdd;
1561 if (!globalVariablesInSomeDestination.empty()) {
1562 transitions *= this->variables.globalVariableRanges;
1566 bool isMarkovian =
false;
1567 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1569 exitRates = this->variables.rowExpressionAdapter->translateExpression(edge.
getRate());
1570 transitions *= exitRates.get();
1575 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1576 if (!this->transientVariables.empty()) {
1579 auto newTransientEdgeAssignments = guardAdd * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1581 newTransientEdgeAssignments *= exitRates.get();
1587 return EdgeDd(isMarkovian, guard, transitions, transientEdgeAssignments, globalVariablesInSomeDestination);
1589 return EdgeDd(edge.
hasRate(), rangedGuard, rangedGuard.template toAdd<ValueType>(),
1594 EdgeDd combineMarkovianEdgesToSingleEdge(std::vector<EdgeDd>
const& edgeDds) {
1597 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1598 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1600 bool overlappingGuards =
false;
1601 for (
auto const& edge : edgeDds) {
1602 STORM_LOG_THROW(edge.isMarkovian, storm::exceptions::WrongFormatException,
"Can only combine Markovian edges.");
1604 if (!overlappingGuards) {
1605 overlappingGuards |= !(guard && edge.guard).
isZero();
1608 guard |= edge.guard;
1609 transitions += edge.transitions;
1610 variableToWritingFragment = joinVariableWritingFragmentMaps(variableToWritingFragment, edge.variableToWritingFragment);
1611 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, edge.transientEdgeAssignments);
1615 STORM_LOG_THROW(!overlappingGuards || transientEdgeAssignments.empty(), storm::exceptions::NotSupportedException,
1616 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1618 return EdgeDd(
true, guard, transitions, transientEdgeAssignments, variableToWritingFragment);
1621 ActionDd buildActionDdForActionInstantiation(
storm::jani::Automaton const& automaton, ActionInstantiation
const& instantiation) {
1623 std::vector<EdgeDd> edgeDds;
1624 for (
auto const& edge : automaton.getEdges()) {
1625 if (edge.
getActionIndex() == instantiation.actionIndex && edge.
hasRate() == instantiation.isMarkovian()) {
1626 EdgeDd result = buildEdgeDd(automaton, edge);
1627 edgeDds.emplace_back(result);
1632 uint64_t localNondeterminismVariableOffset = instantiation.localNondeterminismVariableOffset;
1633 if (!edgeDds.empty()) {
1636 return combineEdgesToActionDeterministic(edgeDds);
1638 return combineEdgesToActionDeterministic(edgeDds);
1640 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1642 if (instantiation.isMarkovian()) {
1643 return combineEdgesToActionDeterministic(edgeDds);
1645 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1648 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Cannot translate model of type " << modelType <<
".");
1651 return ActionDd(this->variables.manager->getBddZero(), this->variables.manager->template getAddZero<ValueType>(), {},
1652 std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
1658 for (
auto const& entry : assignmentsToAdd) {
1659 auto it = transientAssignments.find(entry.first);
1660 if (it != transientAssignments.
end()) {
1661 it->second += entry.second;
1663 transientAssignments[entry.first] = entry.second;
1670 auto it = transientAssignments.find(variable);
1671 if (it != transientAssignments.
end()) {
1672 it->second += assignmentToAdd;
1674 transientAssignments[variable] = assignmentToAdd;
1678 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(
1681 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1;
1683 for (
auto const& entry : transientAssignments2) {
1684 auto resultIt = result.find(entry.first);
1685 if (resultIt != result.end()) {
1686 resultIt->second += entry.second;
1688 result.emplace(entry);
1698 for (
auto const& entry : newTransientAssignments) {
1699 auto targetIt = target.find(entry.first);
1700 if (targetIt != target.end()) {
1701 targetIt->second += factor ? factor.get() * entry.second : entry.second;
1703 target[entry.first] = factor ? factor.get() * entry.second : entry.second;
1708 ActionDd combineEdgesToActionDeterministic(std::vector<EdgeDd>
const& edgeDds) {
1713 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1714 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1715 bool overlappingGuards =
false;
1716 for (
auto const& edgeDd : edgeDds) {
1719 storm::exceptions::WrongFormatException,
"Unexpected edge type.");
1722 overlappingGuards = !(edgeDd.guard && allGuards).
isZero();
1727 "Guard of an edge in a DTMC overlaps with previous guards.");
1730 allGuards |= edgeDd.guard;
1731 allTransitions += edgeDd.transitions;
1736 addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments);
1739 globalVariableToWritingFragment = joinVariableWritingFragmentMaps(globalVariableToWritingFragment, edgeDd.variableToWritingFragment);
1743 storm::exceptions::NotSupportedException,
1744 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1746 return ActionDd(allGuards, allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1747 this->variables.manager->getBddZero());
1752 auto it = globalVariableToWritingFragment.find(variable);
1753 if (it != globalVariableToWritingFragment.end()) {
1754 it->second |= partToAdd;
1756 globalVariableToWritingFragment.emplace(variable, partToAdd);
1762 for (
auto const& entry : partToAdd) {
1763 addToVariableWritingFragmentMap(globalVariableToWritingFragment, entry.first, entry.second);
1767 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> joinVariableWritingFragmentMaps(
1770 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> result = globalVariableToWritingFragment1;
1772 for (
auto const& entry : globalVariableToWritingFragment2) {
1773 auto resultIt = result.find(entry.first);
1774 if (resultIt != result.end()) {
1775 resultIt->second |= entry.second;
1777 result[entry.first] = entry.second;
1784 ActionDd combineEdgesBySummation(
storm::dd::Bdd<Type> const& guard, std::vector<EdgeDd>
const& edges) {
1786 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1787 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1789 for (
auto const& edge : edges) {
1790 transitions += edge.transitions;
1791 for (
auto const& assignment : edge.transientEdgeAssignments) {
1792 addToTransientAssignmentMap(transientEdgeAssignments, assignment.first, assignment.second);
1794 for (
auto const& variableFragment : edge.variableToWritingFragment) {
1795 addToVariableWritingFragmentMap(globalVariableToWritingFragment, variableFragment.first, variableFragment.second);
1799 return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1800 this->variables.manager->getBddZero());
1803 ActionDd combineEdgesToActionNondeterministic(std::vector<EdgeDd>
const& edges, uint64_t localNondeterminismVariableOffset) {
1807 for (
auto const& edge : edges) {
1809 sumOfGuards += edge.guard.template toAdd<uint_fast64_t>();
1810 allGuards |= edge.guard;
1812 uint_fast64_t maxChoices = sumOfGuards.
getMax();
1813 STORM_LOG_TRACE(
"Found " << maxChoices <<
" non-Markovian local choices.");
1816 if (maxChoices <= 1) {
1817 return combineEdgesBySummation(allGuards, edges);
1820 uint_fast64_t numberOfBinaryVariables =
static_cast<uint_fast64_t
>(std::ceil(std::log2(maxChoices)));
1823 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1824 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
1827 std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>());
1828 std::vector<storm::dd::Bdd<Type>> remainingDds(maxChoices, this->variables.manager->getBddZero());
1830 for (uint64_t j = 0; j < maxChoices; ++j) {
1832 indicesEncodedWithLocalNondeterminismVariables.push_back(std::make_pair(indexEncoding.
toBdd(), indexEncoding));
1835 for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
1837 equalsNumberOfChoicesDd = sumOfGuards.
equals(this->variables.manager->getConstant(currentChoices));
1840 if (equalsNumberOfChoicesDd.
isZero()) {
1845 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1846 choiceDds[j] = this->variables.manager->template getAddZero<ValueType>();
1847 remainingDds[j] = equalsNumberOfChoicesDd;
1850 for (std::size_t j = 0; j < edges.size(); ++j) {
1851 EdgeDd
const& currentEdge = edges[j];
1858 if (guardChoicesIntersection.
isZero()) {
1863 for (uint_fast64_t k = 0; k < currentChoices; ++k) {
1865 storm::dd::Bdd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k];
1868 if (!remainingGuardChoicesIntersection.
isZero()) {
1870 remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection;
1873 choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions;
1876 for (
auto const& transientAssignment : currentEdge.transientEdgeAssignments) {
1877 addToTransientAssignmentMap(transientAssignments, transientAssignment.first,
1878 remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second *
1879 indicesEncodedWithLocalNondeterminismVariables[k].second);
1883 for (
auto const& variableFragment : currentEdge.variableToWritingFragment) {
1884 addToVariableWritingFragmentMap(
1885 globalVariableToWritingFragment, variableFragment.first,
1886 remainingGuardChoicesIntersection && variableFragment.second && indicesEncodedWithLocalNondeterminismVariables[k].first);
1891 guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection;
1894 if (guardChoicesIntersection.
isZero()) {
1901 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1902 allEdges += indicesEncodedWithLocalNondeterminismVariables[j].second * choiceDds[j];
1906 sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).
template toAdd<uint_fast64_t>();
1909 return ActionDd(allGuards, allEdges, transientAssignments,
1910 std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables),
1911 globalVariableToWritingFragment, this->variables.manager->getBddZero());
1915 AutomatonDd buildAutomatonDd(std::string
const& automatonName, ActionInstantiations
const& actionInstantiations,
1916 std::set<uint64_t>
const& inputEnabledActionIndices,
bool isTopLevelAutomaton) {
1917 STORM_LOG_TRACE(
"Building DD for automaton '" << automatonName <<
"'.");
1918 AutomatonDd result(this->variables.automatonToIdentityMap.at(automatonName));
1924 for (
auto const& actionInstantiation : actionInstantiations) {
1925 uint64_t actionIndex = actionInstantiation.first;
1929 bool inputEnabled =
false;
1930 if (inputEnabledActionIndices.find(actionIndex) != inputEnabledActionIndices.end()) {
1931 inputEnabled =
true;
1933 for (
auto const& instantiation : actionInstantiation.second) {
1934 STORM_LOG_TRACE(
"Building " << (instantiation.isMarkovian() ?
"(Markovian) " :
"")
1935 << (actionInformation.getActionName(actionIndex).empty() ?
"silent " :
"") <<
"action "
1936 << (actionInformation.getActionName(actionIndex).empty() ?
"" : actionInformation.getActionName(actionIndex) +
" ")
1937 <<
"from offset " << instantiation.localNondeterminismVariableOffset <<
".");
1938 ActionDd actionDd = buildActionDdForActionInstantiation(automaton, instantiation);
1940 actionDd.setIsInputEnabled();
1942 if (applyMaximumProgress && isTopLevelAutomaton && !instantiation.isMarkovian()) {
1943 nonMarkovianActionGuards |= actionDd.guard;
1945 STORM_LOG_TRACE(
"Used local nondeterminism variables are " << actionDd.getLowestLocalNondeterminismVariable() <<
" to "
1946 << actionDd.getHighestLocalNondeterminismVariable() <<
".");
1947 result.actions[ActionIdentification(actionIndex, instantiation.synchronizationVectorIndex, instantiation.isMarkovian())] = actionDd;
1948 result.extendLocalNondeterminismVariables(actionDd.getLocalNondeterminismVariables());
1952 if (applyMaximumProgress && isTopLevelAutomaton) {
1954 result.actions[silentMarkovianActionIdentification].conjunctGuardWith(!nonMarkovianActionGuards);
1957 for (uint64_t locationIndex = 0; locationIndex < automaton.
getNumberOfLocations(); ++locationIndex) {
1958 auto const& location = automaton.
getLocation(locationIndex);
1959 performTransientAssignments(
1960 location.getAssignments().getTransientAssignments(), [
this, &automatonName, locationIndex, &result](
storm::jani::Assignment const& assignment) {
1961 storm::dd::Add<Type, ValueType> assignedValues =
1962 this->variables.manager->getEncoding(this->variables.automatonToLocationDdVariableMap.at(automatonName).first, locationIndex)
1963 .template toAdd<ValueType>() *
1964 this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1966 auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable());
1967 if (it != result.transientLocationAssignments.end()) {
1968 it->second += assignedValues;
1970 result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues;
1978 void addMissingGlobalVariableIdentities(ActionDd& action) {
1982 for (
auto const& variable : this->variables.allGlobalVariables) {
1983 auto it = action.variableToWritingFragment.find(variable);
1984 if (it != action.variableToWritingFragment.end()) {
1985 missingIdentities *=
1986 (it->second).
ite(this->variables.manager->template getAddOne<ValueType>(), this->variables.variableToIdentityMap.at(variable));
1988 missingIdentities *= this->variables.variableToIdentityMap.at(variable);
1992 action.transitions *= missingIdentities;
1995 ComposerResult<Type, ValueType> buildSystemFromAutomaton(AutomatonDd& automaton) {
1998 auto modelType = this->model.getModelType();
2007 uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
2008 STORM_LOG_TRACE(
"Building system from composed automaton; number of used nondeterminism variables is " << numberOfUsedNondeterminismVariables
2012 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2013 std::unordered_set<ActionIdentification, ActionIdentificationHash> containedActions;
2014 for (
auto& action : automaton.actions) {
2015 STORM_LOG_TRACE(
"Treating action with index " << action.first.actionIndex << (action.first.isMarkovian() ?
" (Markovian)" :
"") <<
".");
2017 uint64_t actionIndex = action.first.actionIndex;
2018 bool markovian = action.first.isMarkovian();
2019 ActionIdentification identificationWithoutSynchVector(actionIndex, markovian);
2021 STORM_LOG_THROW(containedActions.find(identificationWithoutSynchVector) == containedActions.end(), storm::exceptions::WrongFormatException,
2022 "Duplicate action " << actionInformation.
getActionName(actionIndex));
2023 containedActions.insert(identificationWithoutSynchVector);
2024 illegalFragment |= action.second.illegalFragment;
2025 addMissingGlobalVariableIdentities(action.second);
2031 encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(),
2032 numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
2034 for (
auto const& transientAssignment : action.second.transientEdgeAssignments) {
2035 addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first,
2036 actionEncoding * missingNondeterminismEncoding * transientAssignment.second);
2039 result += extendedTransitions;
2042 return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment,
2043 numberOfUsedNondeterminismVariables);
2049 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2050 std::unordered_set<uint64_t> actionIndices;
2051 for (
auto& action : automaton.actions) {
2052 STORM_LOG_THROW(actionIndices.find(action.first.actionIndex) == actionIndices.end(), storm::exceptions::WrongFormatException,
2053 "Duplication action " << actionInformation.
getActionName(action.first.actionIndex));
2054 actionIndices.insert(action.first.actionIndex);
2055 illegalFragment |= action.second.illegalFragment;
2056 addMissingGlobalVariableIdentities(action.second);
2057 addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
2058 result += action.second.transitions;
2061 return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0);
2063 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Model type '" << this->model.getModelType() <<
"' not supported.");