305 : model(model), automata(), actionInformation(actionInformation) {
313 this->model.getSystemComposition().accept(*
this, boost::none);
314 STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException,
315 "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata.");
317 STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidArgumentException,
318 "The symbolic JANI model builder currently does not support transient edge destination assignments.");
321 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
322 "Cannot build symbolic model from JANI model that contains non-transient global unbounded integer variables.");
323 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
324 "Cannot build symbolic model from JANI model that contains global non-transient real variables.");
325 for (
auto const& automaton : this->model.getAutomata()) {
326 STORM_LOG_THROW(!automaton.getVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
327 "Cannot build symbolic model from JANI model that contains non-transient unbounded integer variables in automaton '"
328 << automaton.getName() <<
"'.");
330 !automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
331 "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() <<
"'.");
335 return createVariables(manager);
340 STORM_LOG_THROW(it == automata.end(), storm::exceptions::InvalidArgumentException,
341 "Cannot build symbolic model from JANI model whose system composition refers to the automaton '" << composition.
getAutomatonName()
342 <<
"' multiple times.");
349 subcomposition->accept(*
this, data);
358 for (
auto const& nonSilentActionIndex : actionInformation.getNonSilentActionIndices()) {
359 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
360 result.manager->addMetaVariable(actionInformation.getActionName(nonSilentActionIndex));
361 result.actionVariablesMap[nonSilentActionIndex] = variablePair.first;
362 result.allNondeterminismVariables.insert(variablePair.first);
366 uint64_t numberOfNondeterminismVariables = this->model.getNumberOfAutomata();
367 for (
auto const& automaton : this->model.getAutomata()) {
368 numberOfNondeterminismVariables += automaton.getNumberOfEdges();
370 for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
371 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable(
"nondet" + std::to_string(i));
372 result.localNondeterminismVariables.push_back(variablePair.first);
373 result.allNondeterminismVariables.insert(variablePair.first);
377 result.probabilisticNondeterminismVariable = result.manager->addMetaVariable(
"prob").first;
378 result.probabilisticMarker = result.manager->getEncoding(result.probabilisticNondeterminismVariable, 1);
379 result.allNondeterminismVariables.insert(result.probabilisticNondeterminismVariable);
382 for (
auto const& automatonName : this->automata) {
387 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
389 result.automatonToLocationDdVariableMap[automaton.
getName()] = variablePair;
390 result.rowColumnMetaVariablePairs.push_back(variablePair);
392 result.variableToRowMetaVariableMap->emplace(locationExpressionVariable, variablePair.first);
393 result.variableToColumnMetaVariableMap->emplace(locationExpressionVariable, variablePair.second);
396 result.rowMetaVariables.insert(variablePair.first);
397 result.columnMetaVariables.insert(variablePair.second);
400 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
401 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
406 for (
auto const& variable : this->model.getGlobalVariables()) {
408 if (variable.isTransient()) {
412 createVariable(variable, result);
413 globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
415 result.globalVariableRanges = globalVariableRanges.template toAdd<ValueType>();
418 for (
auto const& automaton : this->model.getAutomata()) {
423 std::pair<storm::expressions::Variable, storm::expressions::Variable>
const& locationVariables =
424 result.automatonToLocationDdVariableMap[automaton.
getName()];
425 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(locationVariables.first, locationVariables.second);
426 identity &= variableIdentity;
427 range &= result.manager->getRange(locationVariables.first);
432 if (variable.isTransient()) {
436 createVariable(variable, result);
437 identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
438 range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
441 result.automatonToIdentityMap[automaton.
getName()] = identity.template toAdd<ValueType>();
442 result.automatonToRangeMap[automaton.
getName()] = (range && globalVariableRanges).
template toAdd<ValueType>();
445 ParameterCreator<Type, ValueType> parameterCreator;
446 parameterCreator.create(model, *result.rowExpressionAdapter);
447 if (std::is_same<ValueType, storm::RationalFunction>::value) {
448 result.parameters = parameterCreator.getParameters();
454 void createVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
455 auto const& type = variable.
getType();
456 if (type.isBasicType() && type.asBasicType().isBooleanType()) {
457 createBooleanVariable(variable, result);
458 }
else if (type.isBoundedType() && type.asBoundedType().isIntegerType()) {
459 createBoundedIntegerVariable(variable, result);
461 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Invalid type of variable in JANI model.");
465 void createBoundedIntegerVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
467 STORM_LOG_THROW(type.hasLowerBound(), storm::exceptions::NotSupportedException,
468 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no lower bound.");
469 STORM_LOG_THROW(type.hasUpperBound(), storm::exceptions::NotSupportedException,
470 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no upper bound.");
471 int_fast64_t low = type.getLowerBound().evaluateAsInt();
472 int_fast64_t high = type.getUpperBound().evaluateAsInt();
474 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
477 STORM_LOG_TRACE(
"Created meta variables for global integer variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
480 result.rowMetaVariables.insert(variablePair.first);
483 result.columnMetaVariables.insert(variablePair.second);
484 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
486 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
487 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
488 result.rowColumnMetaVariablePairs.push_back(variablePair);
489 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
490 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
495 void createBooleanVariable(
storm::jani::Variable const& variable, CompositionVariables<Type, ValueType>& result) {
496 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
499 STORM_LOG_TRACE(
"Created meta variables for global boolean variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
502 result.rowMetaVariables.insert(variablePair.first);
505 result.columnMetaVariables.insert(variablePair.second);
506 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
508 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
509 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
511 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
512 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
514 result.rowColumnMetaVariablePairs.push_back(variablePair);
519 std::set<std::string> automata;
690 std::set<storm::expressions::Variable>
const& writtenGlobalVariables)
691 : isMarkovian(isMarkovian),
693 transitions(transitions),
694 transientEdgeAssignments(transientEdgeAssignments),
695 variableToWritingFragment() {
697 for (
auto const& variable : writtenGlobalVariables) {
698 variableToWritingFragment[variable] = guard;
705 : isMarkovian(isMarkovian),
707 transitions(transitions),
708 transientEdgeAssignments(transientEdgeAssignments),
709 variableToWritingFragment(variableToWritingFragment) {
734 std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0),
735 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& variableToWritingFragment = {},
738 transitions(transitions),
739 transientEdgeAssignments(transientEdgeAssignments),
740 localNondeterminismVariables(localNondeterminismVariables),
741 variableToWritingFragment(variableToWritingFragment),
742 illegalFragment(illegalFragment),
743 inputEnabled(false) {
748 return localNondeterminismVariables.first;
752 return localNondeterminismVariables.second;
756 return localNondeterminismVariables;
760 return ActionDd(guard, transitions * factor, transientEdgeAssignments, localNondeterminismVariables, variableToWritingFragment, illegalFragment);
768 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> newTransientEdgeAssignments(this->transientEdgeAssignments);
770 auto it = newTransientEdgeAssignments.find(entry.first);
771 if (it == newTransientEdgeAssignments.end()) {
772 newTransientEdgeAssignments[entry.first] = entry.second;
774 it->second += entry.second;
778 std::pair<uint64_t, uint64_t> newLocalNondeterminismVariables =
783 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> newVariableToWritingFragment(this->variableToWritingFragment);
785 auto it = newVariableToWritingFragment.find(entry.first);
786 if (it == newVariableToWritingFragment.end()) {
787 newVariableToWritingFragment[entry.first] = entry.second;
789 it->second |= entry.second;
796 return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment,
806 transitions *= conditionAdd;
807 for (
auto& t : transientEdgeAssignments) {
808 t.second *= conditionAdd;
810 illegalFragment &= condition;
847 : actionIndex(actionIndex), synchronizationVectorIndex(
boost::none), markovian(markovian) {
852 : actionIndex(actionIndex), synchronizationVectorIndex(synchronizationVectorIndex), markovian(markovian) {
856 ActionIdentification(uint64_t actionIndex, boost::optional<uint64_t> synchronizationVectorIndex,
bool markovian =
false)
857 : actionIndex(actionIndex), synchronizationVectorIndex(synchronizationVectorIndex), markovian(markovian) {
862 this->markovian = markovian;
866 return this->markovian;
871 if (synchronizationVectorIndex) {
892 std::size_t seed = 0;
893 boost::hash_combine(seed, identification.
actionIndex);
897 return identification.
markovian ? ~seed : seed;
906 transientLocationAssignments(transientLocationAssignments),
908 localNondeterminismVariables(
std::make_pair<uint64_t, uint64_t>(0, 0)) {
913 return localNondeterminismVariables.first;
917 localNondeterminismVariables.first = newValue;
921 return localNondeterminismVariables.second;
925 localNondeterminismVariables.second = newValue;
929 setLowestLocalNondeterminismVariable(std::min(localNondeterminismVariables.first, getLowestLocalNondeterminismVariable()));
930 setHighestLocalNondeterminismVariable(std::max(localNondeterminismVariables.second, getHighestLocalNondeterminismVariable()));
934 std::unordered_map<ActionIdentification, ActionDd, ActionIdentificationHash>
actions;
948 bool applyMaximumProgress)
949 :
SystemComposer<Type, ValueType>(model, variables, transientVariables),
950 actionInformation(actionInformation),
951 applyMaximumProgress(applyMaximumProgress) {
959 STORM_LOG_THROW(this->model.hasStandardCompliantComposition(), storm::exceptions::WrongFormatException,
960 "Model builder only supports non-nested parallel compositions.");
961 AutomatonDd globalAutomaton = boost::any_cast<AutomatonDd>(this->model.getSystemComposition().accept(*
this, boost::any()));
962 return buildSystemFromAutomaton(globalAutomaton);
966 ActionInstantiation(uint64_t actionIndex, uint64_t synchronizationVectorIndex, uint64_t localNondeterminismVariableOffset,
bool markovian =
false)
967 : actionIndex(actionIndex),
968 synchronizationVectorIndex(synchronizationVectorIndex),
969 localNondeterminismVariableOffset(localNondeterminismVariableOffset),
970 markovian(markovian) {
974 ActionInstantiation(uint64_t actionIndex, uint64_t localNondeterminismVariableOffset,
bool markovian =
false)
975 : actionIndex(actionIndex), localNondeterminismVariableOffset(localNondeterminismVariableOffset), markovian(markovian) {
980 this->markovian = markovian;
984 return this->markovian;
990 if (synchronizationVectorIndex) {
1012 std::size_t seed = 0;
1013 boost::hash_combine(seed, instantiation.
actionIndex);
1018 return instantiation.
isMarkovian() ? ~seed : seed;
1031 actionInstantiations[actionIndex].emplace_back(actionIndex, 0, isCtmc);
1039 std::set<uint64_t> inputEnabledActionIndices;
1041 inputEnabledActionIndices.insert(actionInformation.
getActionIndex(actionName));
1044 return buildAutomatonDd(composition.
getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data),
1045 inputEnabledActionIndices, data.empty());
1049 STORM_LOG_ASSERT(data.empty(),
"Expected parallel composition to be on topmost level to be JANI compliant.");
1054 std::vector<AutomatonDd> subautomata;
1059 for (uint64_t subcompositionIndex = 0; subcompositionIndex < composition.
getNumberOfSubcompositions(); ++subcompositionIndex) {
1062 actionInstantiations[silentActionIndex].emplace_back(silentActionIndex, 0, isCtmc);
1068 ++synchronizationVectorIndex) {
1074 if (subcompositionIndex == synchVector.getPositionOfFirstParticipatingAction()) {
1075 uint64_t actionIndex = actionInformation.
getActionIndex(synchVector.getInput(subcompositionIndex));
1076 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, 0, isCtmc);
1078 uint64_t actionIndex = actionInformation.
getActionIndex(synchVector.getInput(subcompositionIndex));
1083 boost::optional<uint64_t> previousActionPosition = synchVector.getPositionOfPrecedingParticipatingAction(subcompositionIndex);
1084 STORM_LOG_ASSERT(previousActionPosition,
"Inconsistent information about synchronization vector.");
1085 AutomatonDd const& previousAutomatonDd = subautomata[previousActionPosition.get()];
1086 auto precedingActionIndex = actionInformation.
getActionIndex(synchVector.getInput(previousActionPosition.get()));
1087 auto precedingActionIt = previousAutomatonDd.
actions.find(
ActionIdentification(precedingActionIndex, synchronizationVectorIndex, isCtmc));
1089 uint64_t highestLocalNondeterminismVariable = 0;
1090 if (precedingActionIt != previousAutomatonDd.
actions.end()) {
1091 highestLocalNondeterminismVariable = precedingActionIt->second.getHighestLocalNondeterminismVariable();
1094 <<
" that is mentioned in parallel composition.");
1096 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, highestLocalNondeterminismVariable, isCtmc);
1100 subautomata.push_back(boost::any_cast<AutomatonDd>(composition.
getSubcomposition(subcompositionIndex).
accept(*
this, actionInstantiations)));
1107 AutomatonDd composeInParallel(std::vector<AutomatonDd>
const& subautomata, std::vector<storm::jani::SynchronizationVector>
const& synchronizationVectors) {
1108 AutomatonDd result(this->variables.manager->template getAddOne<ValueType>());
1114 std::unordered_map<ActionIdentification, std::vector<ActionDd>, ActionIdentificationHash> actions;
1115 for (uint64_t synchronizationVectorIndex = 0; synchronizationVectorIndex < synchronizationVectors.size(); ++synchronizationVectorIndex) {
1116 auto const& synchVector = synchronizationVectors[synchronizationVectorIndex];
1118 boost::optional<ActionDd> synchronizingAction = combineSynchronizingActions(subautomata, synchVector, synchronizationVectorIndex);
1119 if (synchronizingAction) {
1120 if (applyMaximumProgress) {
1122 "Maximum progress assumption enabled for unexpected model type.");
1124 nonMarkovianActionGuards |= synchronizingAction->guard;
1126 actions[ActionIdentification(actionInformation.
getActionIndex(synchVector.getOutput()),
1128 .emplace_back(synchronizingAction.get());
1137 std::vector<ActionDd> silentActionDds;
1138 std::vector<ActionDd> silentMarkovianActionDds;
1139 for (
auto const& automaton : subautomata) {
1140 for (
auto& actionDd : silentActionDds) {
1141 STORM_LOG_TRACE(
"Extending previous (non-Markovian) silent action by identity of current automaton.");
1142 actionDd = actionDd.multiplyTransitions(automaton.identity);
1144 for (
auto& actionDd : silentMarkovianActionDds) {
1145 STORM_LOG_TRACE(
"Extending previous (Markovian) silent action by identity of current automaton.");
1146 actionDd = actionDd.multiplyTransitions(automaton.identity);
1149 auto silentActionIt = automaton.actions.find(silentActionIdentification);
1150 if (silentActionIt != automaton.actions.end()) {
1151 STORM_LOG_TRACE(
"Extending (non-Markovian) silent action by running identity.");
1152 silentActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1155 silentActionIt = automaton.actions.find(silentMarkovianActionIdentification);
1156 if (silentActionIt != automaton.actions.end()) {
1157 STORM_LOG_TRACE(
"Extending (Markovian) silent action by running identity.");
1158 silentMarkovianActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1161 result.identity *= automaton.identity;
1164 addToTransientAssignmentMap(result.transientLocationAssignments, automaton.transientLocationAssignments);
1167 if (!silentActionDds.empty()) {
1168 auto& allSilentActionDds = actions[silentActionIdentification];
1169 allSilentActionDds.insert(allSilentActionDds.end(), silentActionDds.begin(), silentActionDds.end());
1173 if (applyMaximumProgress) {
1174 auto allSilentActionDdsIt = actions.find(silentActionIdentification);
1175 if (allSilentActionDdsIt != actions.end()) {
1176 for (ActionDd
const& silentActionDd : allSilentActionDdsIt->second) {
1177 nonMarkovianActionGuards |= silentActionDd.guard;
1182 if (!silentMarkovianActionDds.empty()) {
1183 auto& allMarkovianSilentActionDds = actions[silentMarkovianActionIdentification];
1184 allMarkovianSilentActionDds.insert(allMarkovianSilentActionDds.end(), silentMarkovianActionDds.begin(), silentMarkovianActionDds.end());
1185 if (applyMaximumProgress && !nonMarkovianActionGuards.
isZero()) {
1186 auto invertedNonMarkovianGuards = !nonMarkovianActionGuards;
1187 for (ActionDd& markovianActionDd : allMarkovianSilentActionDds) {
1188 markovianActionDd.conjunctGuardWith(invertedNonMarkovianGuards);
1194 for (
auto const& actionDds : actions) {
1195 ActionDd combinedAction;
1196 if (actionDds.first == silentMarkovianActionIdentification) {
1198 combinedAction = actionDds.second.front();
1199 for (uint64_t i = 1;
i < actionDds.second.size(); ++
i) {
1200 combinedAction = combinedAction.add(actionDds.second[i]);
1203 combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front();
1205 result.actions[actionDds.first] = combinedAction;
1206 result.extendLocalNondeterminismVariables(combinedAction.getLocalNondeterminismVariables());
1210 for (
auto const& subautomaton : subautomata) {
1211 result.identity *= subautomaton.identity;
1217 boost::optional<ActionDd> combineSynchronizingActions(std::vector<AutomatonDd>
const& subautomata,
1219 uint64_t synchronizationVectorIndex) {
1220 std::vector<std::pair<uint64_t, std::reference_wrapper<ActionDd const>>> actions;
1222 for (uint64_t subautomatonIndex = 0; subautomatonIndex < subautomata.size(); ++subautomatonIndex) {
1223 auto const& subautomaton = subautomata[subautomatonIndex];
1226 subautomaton.actions.find(ActionIdentification(actionInformation.
getActionIndex(synchronizationVector.
getInput(subautomatonIndex)),
1228 if (it != subautomaton.actions.end()) {
1229 actions.emplace_back(subautomatonIndex, it->second);
1234 nonSynchronizingIdentity *= subautomaton.identity;
1239 bool allActionsInputEnabled =
true;
1240 for (
auto const& action : actions) {
1241 if (!action.second.get().isInputEnabled()) {
1242 allActionsInputEnabled =
false;
1246 boost::optional<storm::dd::Bdd<Type>> guardDisjunction;
1247 if (allActionsInputEnabled) {
1248 guardDisjunction = this->variables.manager->getBddZero();
1254 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1255 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragmentWithoutNondeterminism;
1260 uint64_t lowestNondeterminismVariable = actions.front().second.get().getLowestLocalNondeterminismVariable();
1261 uint64_t highestNondeterminismVariable = actions.front().second.get().getHighestLocalNondeterminismVariable();
1263 bool hasTransientEdgeAssignments =
false;
1264 for (
auto const& actionIndexPair : actions) {
1265 auto const& action = actionIndexPair.second.get();
1266 if (!action.transientEdgeAssignments.empty()) {
1267 hasTransientEdgeAssignments =
true;
1272 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1273 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1276 exitRates = this->variables.manager->template getAddOne<ValueType>();
1277 for (
auto const& actionIndexPair : actions) {
1278 auto const& action = actionIndexPair.second.get();
1280 std::set<storm::expressions::Variable> columnVariablesToAbstract;
1281 std::set_intersection(action.transitions.getContainedMetaVariables().begin(), action.transitions.getContainedMetaVariables().end(),
1282 this->variables.columnMetaVariables.begin(), this->variables.columnMetaVariables.end(),
1283 std::inserter(columnVariablesToAbstract, columnVariablesToAbstract.begin()));
1284 auto actionExitRates = action.transitions.sumAbstract(columnVariablesToAbstract);
1285 exitRates = exitRates.get() * actionExitRates;
1287 if (!action.transientEdgeAssignments.empty()) {
1288 for (
auto const& entry : action.transientEdgeAssignments) {
1289 auto transientEdgeAssignmentIt = transientEdgeAssignments.find(entry.first);
1290 if (transientEdgeAssignmentIt != transientEdgeAssignments.end()) {
1291 transientEdgeAssignmentIt->second *= entry.second / actionExitRates;
1293 transientEdgeAssignments.emplace(entry.first, entry.second / actionExitRates);
1298 }
else if (hasTransientEdgeAssignments) {
1300 for (
auto const& actionIndexPair : actions) {
1301 auto const& action = actionIndexPair.second.get();
1302 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments);
1307 for (
auto const& actionIndexPair : actions) {
1308 auto componentIndex = actionIndexPair.first;
1309 auto const& action = actionIndexPair.second.get();
1311 if (guardDisjunction) {
1312 guardDisjunction.get() |= action.guard;
1315 lowestNondeterminismVariable = std::min(lowestNondeterminismVariable, action.getLowestLocalNondeterminismVariable());
1316 highestNondeterminismVariable = std::max(highestNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1318 if (action.isInputEnabled()) {
1320 transitions *= action.guard.ite(
1322 encodeIndex(0, action.getLowestLocalNondeterminismVariable(),
1323 action.getHighestLocalNondeterminismVariable() - action.getLowestLocalNondeterminismVariable(), this->variables) *
1324 subautomata[componentIndex].identity);
1326 transitions *= action.transitions;
1330 auto nondetVariables =
1331 std::set<storm::expressions::Variable>(this->variables.localNondeterminismVariables.begin() + action.getLowestLocalNondeterminismVariable(),
1332 this->variables.localNondeterminismVariables.begin() + action.getHighestLocalNondeterminismVariable());
1334 for (
auto const& entry : action.variableToWritingFragment) {
1339 auto globalFragmentIt = globalVariableToWritingFragment.find(entry.first);
1340 if (globalFragmentIt != globalVariableToWritingFragment.end()) {
1343 globalFragmentIt->second &= guardedWritingFragment;
1345 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] && guardedWritingFragment.
existsAbstract(nondetVariables);
1346 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] |= guardedWritingFragment.
existsAbstract(nondetVariables);
1350 globalVariableToWritingFragment[entry.first] = guardedWritingFragment;
1351 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] = guardedWritingFragment.
existsAbstract(nondetVariables);
1356 illegalFragment |= action.illegalFragment;
1361 for (
auto& entry : globalVariableToWritingFragment) {
1362 if (action.variableToWritingFragment.find(entry.first) == action.variableToWritingFragment.end() && !action.isInputEnabled()) {
1363 entry.second &= action.guard;
1367 if (!action.isInputEnabled()) {
1368 inputEnabledGuard &= action.guard;
1374 if (allActionsInputEnabled) {
1375 inputEnabledGuard &= guardDisjunction.get();
1376 transitions *= guardDisjunction.get().template toAdd<ValueType>();
1381 illegalFragment &= inputEnabledGuard;
1384 if (hasTransientEdgeAssignments) {
1385 transientEdgeAssignmentWeights = inputEnabledGuard.template toAdd<ValueType>();
1387 transientEdgeAssignmentWeights *= exitRates.get();
1390 for (
auto& entry : transientEdgeAssignments) {
1391 entry.second *= transientEdgeAssignmentWeights;
1395 return ActionDd(inputEnabledGuard, transitions * nonSynchronizingIdentity, transientEdgeAssignments,
1396 std::make_pair(lowestNondeterminismVariable, highestNondeterminismVariable), globalVariableToWritingFragment, illegalFragment);
1402 STORM_LOG_TRACE(
"Multiplying identities to combine unsynchronized actions.");
1403 action1.transitions = action1.transitions * identity2;
1404 action2.transitions = action2.transitions * identity1;
1407 return combineUnsynchronizedActions(action1, action2);
1410 ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2) {
1411 return combineUnsynchronizedActions({action1, action2});
1414 ActionDd combineUnsynchronizedActions(std::vector<ActionDd> actions) {
1418 auto actionIt = actions.begin();
1419 ActionDd result(*actionIt);
1421 for (++actionIt; actionIt != actions.end(); ++actionIt) {
1422 result = ActionDd(result.guard || actionIt->guard, result.transitions + actionIt->transitions,
1423 joinTransientAssignmentMaps(result.transientEdgeAssignments, actionIt->transientEdgeAssignments),
1424 std::make_pair<uint64_t, uint64_t>(0, 0),
1425 joinVariableWritingFragmentMaps(result.variableToWritingFragment, actionIt->variableToWritingFragment),
1426 result.illegalFragment || actionIt->illegalFragment);
1432 uint_fast64_t lowestLocalNondeterminismVariable = actions.front().getLowestLocalNondeterminismVariable();
1433 uint_fast64_t highestLocalNondeterminismVariable = actions.front().getHighestLocalNondeterminismVariable();
1434 for (
auto const& action : actions) {
1435 STORM_LOG_ASSERT(action.getLowestLocalNondeterminismVariable() == lowestLocalNondeterminismVariable,
1436 "Mismatching lowest nondeterminism variable indices.");
1437 highestLocalNondeterminismVariable = std::max(highestLocalNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1441 for (
auto& action : actions) {
1443 for (uint_fast64_t i = action.getHighestLocalNondeterminismVariable();
i < highestLocalNondeterminismVariable; ++
i) {
1444 nondeterminismEncodingBdd &= this->variables.manager->
getEncoding(this->variables.localNondeterminismVariables[i], 0);
1448 action.transitions *= nondeterminismEncoding;
1450 for (
auto& variableFragment : action.variableToWritingFragment) {
1451 variableFragment.second &= nondeterminismEncodingBdd;
1453 for (
auto& transientAssignment : action.transientEdgeAssignments) {
1454 transientAssignment.second *= nondeterminismEncoding;
1458 uint64_t numberOfLocalNondeterminismVariables =
static_cast<uint64_t
>(std::ceil(std::log2(actions.size())));
1461 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1462 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1465 for (uint64_t actionIndex = 0; actionIndex < actions.size(); ++actionIndex) {
1466 ActionDd& action = actions[actionIndex];
1468 guard |= action.guard;
1471 encodeIndex(actionIndex, highestLocalNondeterminismVariable, numberOfLocalNondeterminismVariables, this->variables);
1472 transitions += nondeterminismEncoding * action.transitions;
1474 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments, nondeterminismEncoding);
1477 for (
auto& entry : action.variableToWritingFragment) {
1478 entry.second &= nondeterminismEncodingBdd;
1480 addToVariableWritingFragmentMap(variableToWritingFragment, action.variableToWritingFragment);
1481 illegalFragment |= action.illegalFragment;
1484 return ActionDd(guard, transitions, transientEdgeAssignments,
1485 std::make_pair(lowestLocalNondeterminismVariable, highestLocalNondeterminismVariable + numberOfLocalNondeterminismVariables),
1486 variableToWritingFragment, illegalFragment);
1488 STORM_LOG_THROW(
false, storm::exceptions::InvalidStateException,
"Illegal model type.");
1494 auto transientVariableIt = this->transientVariables.begin();
1495 auto transientVariableIte = this->transientVariables.end();
1496 for (
auto const& assignment : transientAssignments) {
1497 while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) {
1498 ++transientVariableIt;
1500 if (transientVariableIt == transientVariableIte) {
1503 if (*transientVariableIt == assignment.getExpressionVariable()) {
1504 callback(assignment);
1505 ++transientVariableIt;
1519 if (!rangedGuard.
isZero()) {
1521 std::vector<EdgeDestinationDd<Type, ValueType>> destinationDds;
1525 STORM_LOG_WARN_COND(!destinationDds.back().transitions.isZero(),
"Destination does not have any effect.");
1531 guard = sourceLocationBdd && rangedGuard;
1534 std::set<storm::expressions::Variable> globalVariablesInSomeDestination;
1540 for (
auto const& edgeDestinationDd : destinationDds) {
1541 globalVariablesInSomeDestination.insert(edgeDestinationDd.writtenGlobalVariables.begin(), edgeDestinationDd.writtenGlobalVariables.end());
1544 globalVariablesInSomeDestination = this->variables.allGlobalVariables;
1548 for (
auto& destinationDd : destinationDds) {
1549 std::set<storm::expressions::Variable> missingIdentities;
1550 std::set_difference(globalVariablesInSomeDestination.begin(), globalVariablesInSomeDestination.end(),
1551 destinationDd.writtenGlobalVariables.begin(), destinationDd.writtenGlobalVariables.end(),
1552 std::inserter(missingIdentities, missingIdentities.begin()));
1554 for (
auto const& variable : missingIdentities) {
1556 destinationDd.transitions *= this->variables.variableToIdentityMap.at(variable);
1562 for (
auto const& destinationDd : destinationDds) {
1563 transitions += destinationDd.transitions;
1568 transitions *= guardAdd;
1571 if (!globalVariablesInSomeDestination.empty()) {
1572 transitions *= this->variables.globalVariableRanges;
1576 bool isMarkovian =
false;
1577 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1579 exitRates = this->variables.rowExpressionAdapter->translateExpression(edge.
getRate());
1580 transitions *= exitRates.get();
1585 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1586 if (!this->transientVariables.empty()) {
1589 auto newTransientEdgeAssignments = guardAdd * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1591 newTransientEdgeAssignments *= exitRates.get();
1597 return EdgeDd(isMarkovian, guard, transitions, transientEdgeAssignments, globalVariablesInSomeDestination);
1599 return EdgeDd(edge.
hasRate(), rangedGuard, rangedGuard.template toAdd<ValueType>(),
1604 EdgeDd combineMarkovianEdgesToSingleEdge(std::vector<EdgeDd>
const& edgeDds) {
1607 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1608 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1610 bool overlappingGuards =
false;
1611 for (
auto const& edge : edgeDds) {
1612 STORM_LOG_THROW(edge.isMarkovian, storm::exceptions::WrongFormatException,
"Can only combine Markovian edges.");
1614 if (!overlappingGuards) {
1615 overlappingGuards |= !(guard && edge.guard).
isZero();
1618 guard |= edge.guard;
1619 transitions += edge.transitions;
1620 variableToWritingFragment = joinVariableWritingFragmentMaps(variableToWritingFragment, edge.variableToWritingFragment);
1621 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, edge.transientEdgeAssignments);
1625 STORM_LOG_THROW(!overlappingGuards || transientEdgeAssignments.empty(), storm::exceptions::NotSupportedException,
1626 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1628 return EdgeDd(
true, guard, transitions, transientEdgeAssignments, variableToWritingFragment);
1631 ActionDd buildActionDdForActionInstantiation(
storm::jani::Automaton const& automaton, ActionInstantiation
const& instantiation) {
1633 std::vector<EdgeDd> edgeDds;
1634 for (
auto const& edge : automaton.getEdges()) {
1635 if (edge.
getActionIndex() == instantiation.actionIndex && edge.
hasRate() == instantiation.isMarkovian()) {
1636 EdgeDd result = buildEdgeDd(automaton, edge);
1637 edgeDds.emplace_back(result);
1642 uint64_t localNondeterminismVariableOffset = instantiation.localNondeterminismVariableOffset;
1643 if (!edgeDds.empty()) {
1646 return combineEdgesToActionDeterministic(edgeDds);
1648 return combineEdgesToActionDeterministic(edgeDds);
1650 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1652 if (instantiation.isMarkovian()) {
1653 return combineEdgesToActionDeterministic(edgeDds);
1655 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1658 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Cannot translate model of type " << modelType <<
".");
1661 return ActionDd(this->variables.manager->getBddZero(), this->variables.manager->template getAddZero<ValueType>(), {},
1662 std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
1668 for (
auto const& entry : assignmentsToAdd) {
1669 auto it = transientAssignments.find(entry.first);
1670 if (it != transientAssignments.
end()) {
1671 it->second += entry.second;
1673 transientAssignments[entry.first] = entry.second;
1680 auto it = transientAssignments.find(variable);
1681 if (it != transientAssignments.
end()) {
1682 it->second += assignmentToAdd;
1684 transientAssignments[variable] = assignmentToAdd;
1688 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(
1691 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1;
1693 for (
auto const& entry : transientAssignments2) {
1694 auto resultIt = result.find(entry.first);
1695 if (resultIt != result.end()) {
1696 resultIt->second += entry.second;
1698 result.emplace(entry);
1708 for (
auto const& entry : newTransientAssignments) {
1709 auto targetIt = target.find(entry.first);
1710 if (targetIt != target.end()) {
1711 targetIt->second += factor ? factor.get() * entry.second : entry.second;
1713 target[entry.first] = factor ? factor.get() * entry.second : entry.second;
1718 ActionDd combineEdgesToActionDeterministic(std::vector<EdgeDd>
const& edgeDds) {
1723 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1724 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1725 bool overlappingGuards =
false;
1726 for (
auto const& edgeDd : edgeDds) {
1729 storm::exceptions::WrongFormatException,
"Unexpected edge type.");
1732 overlappingGuards = !(edgeDd.guard && allGuards).
isZero();
1737 "Guard of an edge in a DTMC overlaps with previous guards.");
1740 allGuards |= edgeDd.guard;
1741 allTransitions += edgeDd.transitions;
1746 addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments);
1749 globalVariableToWritingFragment = joinVariableWritingFragmentMaps(globalVariableToWritingFragment, edgeDd.variableToWritingFragment);
1753 storm::exceptions::NotSupportedException,
1754 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1756 return ActionDd(allGuards, allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1757 this->variables.manager->getBddZero());
1762 auto it = globalVariableToWritingFragment.find(variable);
1763 if (it != globalVariableToWritingFragment.end()) {
1764 it->second |= partToAdd;
1766 globalVariableToWritingFragment.emplace(variable, partToAdd);
1772 for (
auto const& entry : partToAdd) {
1773 addToVariableWritingFragmentMap(globalVariableToWritingFragment, entry.first, entry.second);
1777 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> joinVariableWritingFragmentMaps(
1780 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> result = globalVariableToWritingFragment1;
1782 for (
auto const& entry : globalVariableToWritingFragment2) {
1783 auto resultIt = result.find(entry.first);
1784 if (resultIt != result.end()) {
1785 resultIt->second |= entry.second;
1787 result[entry.first] = entry.second;
1794 ActionDd combineEdgesBySummation(
storm::dd::Bdd<Type> const& guard, std::vector<EdgeDd>
const& edges) {
1796 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1797 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1799 for (
auto const& edge : edges) {
1800 transitions += edge.transitions;
1801 for (
auto const& assignment : edge.transientEdgeAssignments) {
1802 addToTransientAssignmentMap(transientEdgeAssignments, assignment.first, assignment.second);
1804 for (
auto const& variableFragment : edge.variableToWritingFragment) {
1805 addToVariableWritingFragmentMap(globalVariableToWritingFragment, variableFragment.first, variableFragment.second);
1809 return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1810 this->variables.manager->getBddZero());
1813 ActionDd combineEdgesToActionNondeterministic(std::vector<EdgeDd>
const& edges, uint64_t localNondeterminismVariableOffset) {
1817 for (
auto const& edge : edges) {
1819 sumOfGuards += edge.guard.template toAdd<uint_fast64_t>();
1820 allGuards |= edge.guard;
1822 uint_fast64_t maxChoices = sumOfGuards.
getMax();
1823 STORM_LOG_TRACE(
"Found " << maxChoices <<
" non-Markovian local choices.");
1826 if (maxChoices <= 1) {
1827 return combineEdgesBySummation(allGuards, edges);
1833 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1834 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
1837 std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>());
1838 std::vector<storm::dd::Bdd<Type>> remainingDds(maxChoices, this->variables.manager->getBddZero());
1840 for (uint64_t j = 0; j < maxChoices; ++j) {
1842 indicesEncodedWithLocalNondeterminismVariables.push_back(std::make_pair(indexEncoding.
toBdd(), indexEncoding));
1845 for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
1847 equalsNumberOfChoicesDd = sumOfGuards.
equals(this->variables.manager->getConstant(currentChoices));
1850 if (equalsNumberOfChoicesDd.
isZero()) {
1855 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1856 choiceDds[j] = this->variables.manager->template getAddZero<ValueType>();
1857 remainingDds[j] = equalsNumberOfChoicesDd;
1860 for (std::size_t j = 0; j < edges.size(); ++j) {
1861 EdgeDd
const& currentEdge = edges[j];
1868 if (guardChoicesIntersection.
isZero()) {
1873 for (uint_fast64_t k = 0; k < currentChoices; ++k) {
1875 storm::dd::Bdd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k];
1878 if (!remainingGuardChoicesIntersection.
isZero()) {
1880 remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection;
1883 choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions;
1886 for (
auto const& transientAssignment : currentEdge.transientEdgeAssignments) {
1887 addToTransientAssignmentMap(transientAssignments, transientAssignment.first,
1888 remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second *
1889 indicesEncodedWithLocalNondeterminismVariables[k].second);
1893 for (
auto const& variableFragment : currentEdge.variableToWritingFragment) {
1894 addToVariableWritingFragmentMap(
1895 globalVariableToWritingFragment, variableFragment.first,
1896 remainingGuardChoicesIntersection && variableFragment.second && indicesEncodedWithLocalNondeterminismVariables[k].first);
1901 guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection;
1904 if (guardChoicesIntersection.
isZero()) {
1911 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1912 allEdges += indicesEncodedWithLocalNondeterminismVariables[j].second * choiceDds[j];
1916 sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).
template toAdd<uint_fast64_t>();
1919 return ActionDd(allGuards, allEdges, transientAssignments,
1920 std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables),
1921 globalVariableToWritingFragment, this->variables.manager->getBddZero());
1925 AutomatonDd buildAutomatonDd(std::string
const& automatonName, ActionInstantiations
const& actionInstantiations,
1926 std::set<uint64_t>
const& inputEnabledActionIndices,
bool isTopLevelAutomaton) {
1927 STORM_LOG_TRACE(
"Building DD for automaton '" << automatonName <<
"'.");
1928 AutomatonDd result(this->variables.automatonToIdentityMap.at(automatonName));
1934 for (
auto const& actionInstantiation : actionInstantiations) {
1935 uint64_t actionIndex = actionInstantiation.first;
1939 bool inputEnabled =
false;
1940 if (inputEnabledActionIndices.find(actionIndex) != inputEnabledActionIndices.end()) {
1941 inputEnabled =
true;
1943 for (
auto const& instantiation : actionInstantiation.second) {
1944 STORM_LOG_TRACE(
"Building " << (instantiation.isMarkovian() ?
"(Markovian) " :
"")
1945 << (actionInformation.getActionName(actionIndex).empty() ?
"silent " :
"") <<
"action "
1946 << (actionInformation.getActionName(actionIndex).empty() ?
"" : actionInformation.getActionName(actionIndex) +
" ")
1947 <<
"from offset " << instantiation.localNondeterminismVariableOffset <<
".");
1948 ActionDd actionDd = buildActionDdForActionInstantiation(automaton, instantiation);
1950 actionDd.setIsInputEnabled();
1952 if (applyMaximumProgress && isTopLevelAutomaton && !instantiation.isMarkovian()) {
1953 nonMarkovianActionGuards |= actionDd.guard;
1955 STORM_LOG_TRACE(
"Used local nondeterminism variables are " << actionDd.getLowestLocalNondeterminismVariable() <<
" to "
1956 << actionDd.getHighestLocalNondeterminismVariable() <<
".");
1957 result.actions[ActionIdentification(actionIndex, instantiation.synchronizationVectorIndex, instantiation.isMarkovian())] = actionDd;
1958 result.extendLocalNondeterminismVariables(actionDd.getLocalNondeterminismVariables());
1962 if (applyMaximumProgress && isTopLevelAutomaton) {
1964 result.actions[silentMarkovianActionIdentification].conjunctGuardWith(!nonMarkovianActionGuards);
1967 for (uint64_t locationIndex = 0; locationIndex < automaton.
getNumberOfLocations(); ++locationIndex) {
1968 auto const& location = automaton.
getLocation(locationIndex);
1969 performTransientAssignments(
1970 location.getAssignments().getTransientAssignments(), [
this, &automatonName, locationIndex, &result](
storm::jani::Assignment const& assignment) {
1971 storm::dd::Add<Type, ValueType> assignedValues =
1972 this->variables.manager->getEncoding(this->variables.automatonToLocationDdVariableMap.at(automatonName).first, locationIndex)
1973 .template toAdd<ValueType>() *
1974 this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1976 auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable());
1977 if (it != result.transientLocationAssignments.end()) {
1978 it->second += assignedValues;
1980 result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues;
1988 void addMissingGlobalVariableIdentities(ActionDd& action) {
1992 for (
auto const& variable : this->variables.allGlobalVariables) {
1993 auto it = action.variableToWritingFragment.find(variable);
1994 if (it != action.variableToWritingFragment.end()) {
1995 missingIdentities *=
1996 (it->second).
ite(this->variables.manager->template getAddOne<ValueType>(), this->variables.variableToIdentityMap.at(variable));
1998 missingIdentities *= this->variables.variableToIdentityMap.at(variable);
2002 action.transitions *= missingIdentities;
2005 ComposerResult<Type, ValueType> buildSystemFromAutomaton(AutomatonDd& automaton) {
2008 auto modelType = this->model.getModelType();
2017 uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
2018 STORM_LOG_TRACE(
"Building system from composed automaton; number of used nondeterminism variables is " << numberOfUsedNondeterminismVariables
2022 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2023 std::unordered_set<ActionIdentification, ActionIdentificationHash> containedActions;
2024 for (
auto& action : automaton.actions) {
2025 STORM_LOG_TRACE(
"Treating action with index " << action.first.actionIndex << (action.first.isMarkovian() ?
" (Markovian)" :
"") <<
".");
2027 uint64_t actionIndex = action.first.actionIndex;
2028 bool markovian = action.first.isMarkovian();
2029 ActionIdentification identificationWithoutSynchVector(actionIndex, markovian);
2031 STORM_LOG_THROW(containedActions.find(identificationWithoutSynchVector) == containedActions.end(), storm::exceptions::WrongFormatException,
2032 "Duplicate action " << actionInformation.
getActionName(actionIndex));
2033 containedActions.insert(identificationWithoutSynchVector);
2034 illegalFragment |= action.second.illegalFragment;
2035 addMissingGlobalVariableIdentities(action.second);
2041 encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(),
2042 numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
2044 for (
auto const& transientAssignment : action.second.transientEdgeAssignments) {
2045 addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first,
2046 actionEncoding * missingNondeterminismEncoding * transientAssignment.second);
2049 result += extendedTransitions;
2052 return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment,
2053 numberOfUsedNondeterminismVariables);
2059 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2060 std::unordered_set<uint64_t> actionIndices;
2061 for (
auto& action : automaton.actions) {
2062 STORM_LOG_THROW(actionIndices.find(action.first.actionIndex) == actionIndices.end(), storm::exceptions::WrongFormatException,
2063 "Duplication action " << actionInformation.
getActionName(action.first.actionIndex));
2064 actionIndices.insert(action.first.actionIndex);
2065 illegalFragment |= action.second.illegalFragment;
2066 addMissingGlobalVariableIdentities(action.second);
2067 addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
2068 result += action.second.transitions;
2071 return ComposerResult<Type, ValueType>(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, 0);
2073 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Model type '" << this->model.getModelType() <<
"' not supported.");