293 : model(model), automata(), actionInformation(actionInformation) {
301 this->model.getSystemComposition().accept(*
this, boost::none);
302 STORM_LOG_THROW(automata.size() == this->model.getNumberOfAutomata(), storm::exceptions::InvalidArgumentException,
303 "Cannot build symbolic model from JANI model whose system composition refers to a subset of automata.");
305 STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidArgumentException,
306 "The symbolic JANI model builder currently does not support transient edge destination assignments.");
309 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
310 "Cannot build symbolic model from JANI model that contains non-transient global unbounded integer variables.");
311 STORM_LOG_THROW(!this->model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
312 "Cannot build symbolic model from JANI model that contains global non-transient real variables.");
313 for (
auto const& automaton : this->model.getAutomata()) {
314 STORM_LOG_THROW(!automaton.getVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException,
315 "Cannot build symbolic model from JANI model that contains non-transient unbounded integer variables in automaton '"
316 << automaton.getName() <<
"'.");
318 !automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException,
319 "Cannot build symbolic model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() <<
"'.");
323 return createVariables(manager);
328 STORM_LOG_THROW(it == automata.end(), storm::exceptions::InvalidArgumentException,
329 "Cannot build symbolic model from JANI model whose system composition refers to the automaton '" << composition.
getAutomatonName()
330 <<
"' multiple times.");
337 subcomposition->accept(*
this, data);
346 for (
auto const& nonSilentActionIndex : actionInformation.getNonSilentActionIndices()) {
347 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
348 result.manager->addMetaVariable(actionInformation.getActionName(nonSilentActionIndex));
349 result.actionVariablesMap[nonSilentActionIndex] = variablePair.first;
350 result.allNondeterminismVariables.insert(variablePair.first);
354 uint64_t numberOfNondeterminismVariables = this->model.getNumberOfAutomata();
355 for (
auto const& automaton : this->model.getAutomata()) {
356 numberOfNondeterminismVariables += automaton.getNumberOfEdges();
358 for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
359 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable(
"nondet" + std::to_string(i));
360 result.localNondeterminismVariables.push_back(variablePair.first);
361 result.allNondeterminismVariables.insert(variablePair.first);
365 result.probabilisticNondeterminismVariable = result.manager->addMetaVariable(
"prob").first;
366 result.probabilisticMarker = result.manager->getEncoding(result.probabilisticNondeterminismVariable, 1);
367 result.allNondeterminismVariables.insert(result.probabilisticNondeterminismVariable);
370 for (
auto const& automatonName : this->automata) {
371 storm::jani::Automaton
const& automaton = this->model.getAutomaton(automatonName);
375 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
377 result.automatonToLocationDdVariableMap[automaton.
getName()] = variablePair;
378 result.rowColumnMetaVariablePairs.push_back(variablePair);
380 result.variableToRowMetaVariableMap->emplace(locationExpressionVariable, variablePair.first);
381 result.variableToColumnMetaVariableMap->emplace(locationExpressionVariable, variablePair.second);
384 result.rowMetaVariables.insert(variablePair.first);
385 result.columnMetaVariables.insert(variablePair.second);
388 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
389 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
393 storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne();
394 for (
auto const& variable : this->model.getGlobalVariables()) {
396 if (variable.isTransient()) {
400 createVariable(variable, result);
401 globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
403 result.globalVariableRanges = globalVariableRanges.template toAdd<ValueType>();
406 for (
auto const& automaton : this->model.getAutomata()) {
407 storm::dd::Bdd<Type> identity = result.manager->getBddOne();
408 storm::dd::Bdd<Type> range = result.manager->getBddOne();
411 std::pair<storm::expressions::Variable, storm::expressions::Variable>
const& locationVariables =
412 result.automatonToLocationDdVariableMap[automaton.
getName()];
413 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(locationVariables.first, locationVariables.second);
414 identity &= variableIdentity;
415 range &= result.manager->getRange(locationVariables.first);
420 if (variable.isTransient()) {
424 createVariable(variable, result);
425 identity &= result.variableToIdentityMap.at(variable.getExpressionVariable()).toBdd();
426 range &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable()));
429 result.automatonToIdentityMap[automaton.
getName()] = identity.template toAdd<ValueType>();
430 result.automatonToRangeMap[automaton.
getName()] = (range && globalVariableRanges).
template toAdd<ValueType>();
433 ParameterCreator<Type, ValueType> parameterCreator;
434 parameterCreator.create(model, *result.rowExpressionAdapter);
435 if (std::is_same<ValueType, storm::RationalFunction>::value) {
436 result.parameters = parameterCreator.getParameters();
442 void createVariable(storm::jani::Variable
const& variable, CompositionVariables<Type, ValueType>& result) {
443 auto const& type = variable.
getType();
444 if (type.isBasicType() && type.asBasicType().isBooleanType()) {
445 createBooleanVariable(variable, result);
446 }
else if (type.isBoundedType() && type.asBoundedType().isIntegerType()) {
447 createBoundedIntegerVariable(variable, result);
449 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Invalid type of variable in JANI model.");
453 void createBoundedIntegerVariable(storm::jani::Variable
const& variable, CompositionVariables<Type, ValueType>& result) {
455 STORM_LOG_THROW(type.hasLowerBound(), storm::exceptions::NotSupportedException,
456 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no lower bound.");
457 STORM_LOG_THROW(type.hasUpperBound(), storm::exceptions::NotSupportedException,
458 "DdJaniModelBuilder only supports bounded variables. Variable " << variable.
getName() <<
" has no upper bound.");
459 int_fast64_t low = type.getLowerBound().evaluateAsInt();
460 int_fast64_t high = type.getUpperBound().evaluateAsInt();
462 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
465 STORM_LOG_TRACE(
"Created meta variables for global integer variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
468 result.rowMetaVariables.insert(variablePair.first);
471 result.columnMetaVariables.insert(variablePair.second);
472 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
474 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
475 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
476 result.rowColumnMetaVariablePairs.push_back(variablePair);
477 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
478 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
483 void createBooleanVariable(storm::jani::Variable
const& variable, CompositionVariables<Type, ValueType>& result) {
484 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
487 STORM_LOG_TRACE(
"Created meta variables for global boolean variable: " << variablePair.first.getName() <<
" and " << variablePair.second.getName()
490 result.rowMetaVariables.insert(variablePair.first);
493 result.columnMetaVariables.insert(variablePair.second);
494 result.variableToColumnMetaVariableMap->emplace(variable.
getExpressionVariable(), variablePair.second);
496 storm::dd::Bdd<Type> variableIdentity = result.manager->getIdentity(variablePair.first, variablePair.second);
497 result.variableToIdentityMap.emplace(variable.
getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
499 result.variableToRangeMap.emplace(variablePair.first, result.manager->getRange(variablePair.first));
500 result.variableToRangeMap.emplace(variablePair.second, result.manager->getRange(variablePair.second));
502 result.rowColumnMetaVariablePairs.push_back(variablePair);
506 storm::jani::Model
const& model;
507 std::set<std::string> automata;
508 storm::jani::CompositionInformation actionInformation;
678 std::set<storm::expressions::Variable>
const& writtenGlobalVariables)
685 for (
auto const& variable : writtenGlobalVariables) {
722 std::pair<uint64_t, uint64_t> localNondeterminismVariables = std::pair<uint64_t, uint64_t>(0, 0),
723 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& variableToWritingFragment = {},
726 transitions(transitions),
727 transientEdgeAssignments(transientEdgeAssignments),
728 localNondeterminismVariables(localNondeterminismVariables),
729 variableToWritingFragment(variableToWritingFragment),
730 illegalFragment(illegalFragment),
731 inputEnabled(false) {
756 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> newTransientEdgeAssignments(this->
transientEdgeAssignments);
758 auto it = newTransientEdgeAssignments.find(entry.first);
759 if (it == newTransientEdgeAssignments.end()) {
760 newTransientEdgeAssignments[entry.first] = entry.second;
762 it->second += entry.second;
766 std::pair<uint64_t, uint64_t> newLocalNondeterminismVariables =
771 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> newVariableToWritingFragment(this->
variableToWritingFragment);
773 auto it = newVariableToWritingFragment.find(entry.first);
774 if (it == newVariableToWritingFragment.end()) {
775 newVariableToWritingFragment[entry.first] = entry.second;
777 it->second |= entry.second;
784 return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment,
796 t.second *= conditionAdd;
880 std::size_t seed = 0;
881 boost::hash_combine(seed, identification.
actionIndex);
885 return identification.
markovian ? ~seed : seed;
894 transientLocationAssignments(transientLocationAssignments),
896 localNondeterminismVariables(
std::make_pair<uint64_t, uint64_t>(0, 0)) {
922 std::unordered_map<ActionIdentification, ActionDd, ActionIdentificationHash>
actions;
947 STORM_LOG_THROW(this->
model.hasStandardCompliantComposition(), storm::exceptions::WrongFormatException,
948 "Model builder only supports non-nested parallel compositions.");
949 AutomatonDd globalAutomaton = boost::any_cast<AutomatonDd>(this->
model.getSystemComposition().accept(*
this, boost::any()));
950 return buildSystemFromAutomaton(globalAutomaton);
1000 std::size_t seed = 0;
1001 boost::hash_combine(seed, instantiation.
actionIndex);
1006 return instantiation.
isMarkovian() ? ~seed : seed;
1019 actionInstantiations[actionIndex].emplace_back(actionIndex, 0, isCtmc);
1027 std::set<uint64_t> inputEnabledActionIndices;
1032 return buildAutomatonDd(composition.
getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data),
1033 inputEnabledActionIndices, data.empty());
1037 STORM_LOG_ASSERT(data.empty(),
"Expected parallel composition to be on topmost level to be JANI compliant.");
1042 std::vector<AutomatonDd> subautomata;
1047 for (uint64_t subcompositionIndex = 0; subcompositionIndex < composition.
getNumberOfSubcompositions(); ++subcompositionIndex) {
1050 actionInstantiations[silentActionIndex].emplace_back(silentActionIndex, 0, isCtmc);
1056 ++synchronizationVectorIndex) {
1062 if (subcompositionIndex == synchVector.getPositionOfFirstParticipatingAction()) {
1063 uint64_t actionIndex =
actionInformation.getActionIndex(synchVector.getInput(subcompositionIndex));
1064 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, 0, isCtmc);
1066 uint64_t actionIndex =
actionInformation.getActionIndex(synchVector.getInput(subcompositionIndex));
1071 boost::optional<uint64_t> previousActionPosition = synchVector.getPositionOfPrecedingParticipatingAction(subcompositionIndex);
1072 STORM_LOG_ASSERT(previousActionPosition,
"Inconsistent information about synchronization vector.");
1073 AutomatonDd const& previousAutomatonDd = subautomata[previousActionPosition.get()];
1074 auto precedingActionIndex =
actionInformation.getActionIndex(synchVector.getInput(previousActionPosition.get()));
1075 auto precedingActionIt = previousAutomatonDd.
actions.find(
ActionIdentification(precedingActionIndex, synchronizationVectorIndex, isCtmc));
1077 uint64_t highestLocalNondeterminismVariable = 0;
1078 if (precedingActionIt != previousAutomatonDd.
actions.end()) {
1079 highestLocalNondeterminismVariable = precedingActionIt->second.getHighestLocalNondeterminismVariable();
1082 <<
" that is mentioned in parallel composition.");
1084 actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, highestLocalNondeterminismVariable, isCtmc);
1088 subautomata.push_back(boost::any_cast<AutomatonDd>(composition.
getSubcomposition(subcompositionIndex).
accept(*
this, actionInstantiations)));
1095 AutomatonDd composeInParallel(std::vector<AutomatonDd>
const& subautomata, std::vector<storm::jani::SynchronizationVector>
const& synchronizationVectors) {
1096 AutomatonDd result(this->variables.manager->template getAddOne<ValueType>());
1102 std::unordered_map<ActionIdentification, std::vector<ActionDd>, ActionIdentificationHash> actions;
1103 for (uint64_t synchronizationVectorIndex = 0; synchronizationVectorIndex < synchronizationVectors.size(); ++synchronizationVectorIndex) {
1104 auto const& synchVector = synchronizationVectors[synchronizationVectorIndex];
1106 boost::optional<ActionDd> synchronizingAction = combineSynchronizingActions(subautomata, synchVector, synchronizationVectorIndex);
1107 if (synchronizingAction) {
1108 if (applyMaximumProgress) {
1110 "Maximum progress assumption enabled for unexpected model type.");
1112 nonMarkovianActionGuards |= synchronizingAction->guard;
1114 actions[ActionIdentification(actionInformation.
getActionIndex(synchVector.getOutput()),
1116 .emplace_back(synchronizingAction.get());
1125 std::vector<ActionDd> silentActionDds;
1126 std::vector<ActionDd> silentMarkovianActionDds;
1127 for (
auto const& automaton : subautomata) {
1128 for (
auto& actionDd : silentActionDds) {
1129 STORM_LOG_TRACE(
"Extending previous (non-Markovian) silent action by identity of current automaton.");
1130 actionDd = actionDd.multiplyTransitions(automaton.identity);
1132 for (
auto& actionDd : silentMarkovianActionDds) {
1133 STORM_LOG_TRACE(
"Extending previous (Markovian) silent action by identity of current automaton.");
1134 actionDd = actionDd.multiplyTransitions(automaton.identity);
1137 auto silentActionIt = automaton.actions.find(silentActionIdentification);
1138 if (silentActionIt != automaton.actions.end()) {
1139 STORM_LOG_TRACE(
"Extending (non-Markovian) silent action by running identity.");
1140 silentActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1143 silentActionIt = automaton.actions.find(silentMarkovianActionIdentification);
1144 if (silentActionIt != automaton.actions.end()) {
1145 STORM_LOG_TRACE(
"Extending (Markovian) silent action by running identity.");
1146 silentMarkovianActionDds.emplace_back(silentActionIt->second.multiplyTransitions(result.identity));
1149 result.identity *= automaton.identity;
1152 addToTransientAssignmentMap(result.transientLocationAssignments, automaton.transientLocationAssignments);
1155 if (!silentActionDds.empty()) {
1156 auto& allSilentActionDds = actions[silentActionIdentification];
1157 allSilentActionDds.insert(allSilentActionDds.end(), silentActionDds.begin(), silentActionDds.end());
1161 if (applyMaximumProgress) {
1162 auto allSilentActionDdsIt = actions.find(silentActionIdentification);
1163 if (allSilentActionDdsIt != actions.end()) {
1164 for (ActionDd
const& silentActionDd : allSilentActionDdsIt->second) {
1165 nonMarkovianActionGuards |= silentActionDd.guard;
1170 if (!silentMarkovianActionDds.empty()) {
1171 auto& allMarkovianSilentActionDds = actions[silentMarkovianActionIdentification];
1172 allMarkovianSilentActionDds.insert(allMarkovianSilentActionDds.end(), silentMarkovianActionDds.begin(), silentMarkovianActionDds.end());
1173 if (applyMaximumProgress && !nonMarkovianActionGuards.
isZero()) {
1174 auto invertedNonMarkovianGuards = !nonMarkovianActionGuards;
1175 for (ActionDd& markovianActionDd : allMarkovianSilentActionDds) {
1176 markovianActionDd.conjunctGuardWith(invertedNonMarkovianGuards);
1182 for (
auto const& actionDds : actions) {
1183 ActionDd combinedAction;
1184 if (actionDds.first == silentMarkovianActionIdentification) {
1186 combinedAction = actionDds.second.front();
1187 for (uint64_t i = 1;
i < actionDds.second.size(); ++
i) {
1188 combinedAction = combinedAction.add(actionDds.second[i]);
1191 combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front();
1193 result.actions[actionDds.first] = combinedAction;
1194 result.extendLocalNondeterminismVariables(combinedAction.getLocalNondeterminismVariables());
1198 for (
auto const& subautomaton : subautomata) {
1199 result.identity *= subautomaton.identity;
1205 boost::optional<ActionDd> combineSynchronizingActions(std::vector<AutomatonDd>
const& subautomata,
1206 storm::jani::SynchronizationVector
const& synchronizationVector,
1207 uint64_t synchronizationVectorIndex) {
1208 std::vector<std::pair<uint64_t, std::reference_wrapper<ActionDd const>>> actions;
1209 storm::dd::Add<Type, ValueType> nonSynchronizingIdentity = this->variables.manager->template getAddOne<ValueType>();
1210 for (uint64_t subautomatonIndex = 0; subautomatonIndex < subautomata.size(); ++subautomatonIndex) {
1211 auto const& subautomaton = subautomata[subautomatonIndex];
1214 subautomaton.actions.find(ActionIdentification(actionInformation.
getActionIndex(synchronizationVector.
getInput(subautomatonIndex)),
1216 if (it != subautomaton.actions.end()) {
1217 actions.emplace_back(subautomatonIndex, it->second);
1222 nonSynchronizingIdentity *= subautomaton.identity;
1227 bool allActionsInputEnabled =
true;
1228 for (
auto const& action : actions) {
1229 if (!action.second.get().isInputEnabled()) {
1230 allActionsInputEnabled =
false;
1234 boost::optional<storm::dd::Bdd<Type>> guardDisjunction;
1235 if (allActionsInputEnabled) {
1236 guardDisjunction = this->variables.manager->getBddZero();
1240 storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
1242 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1243 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragmentWithoutNondeterminism;
1245 storm::dd::Bdd<Type> inputEnabledGuard = this->variables.manager->getBddOne();
1246 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddOne<ValueType>();
1248 uint64_t lowestNondeterminismVariable = actions.front().second.get().getLowestLocalNondeterminismVariable();
1249 uint64_t highestNondeterminismVariable = actions.front().second.get().getHighestLocalNondeterminismVariable();
1251 bool hasTransientEdgeAssignments =
false;
1252 for (
auto const& actionIndexPair : actions) {
1253 auto const& action = actionIndexPair.second.get();
1254 if (!action.transientEdgeAssignments.empty()) {
1255 hasTransientEdgeAssignments =
true;
1260 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1261 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1264 exitRates = this->variables.manager->template getAddOne<ValueType>();
1265 for (
auto const& actionIndexPair : actions) {
1266 auto const& action = actionIndexPair.second.get();
1268 std::set<storm::expressions::Variable> columnVariablesToAbstract;
1269 std::set_intersection(action.transitions.getContainedMetaVariables().begin(), action.transitions.getContainedMetaVariables().end(),
1270 this->variables.columnMetaVariables.begin(), this->variables.columnMetaVariables.end(),
1271 std::inserter(columnVariablesToAbstract, columnVariablesToAbstract.begin()));
1272 auto actionExitRates = action.transitions.sumAbstract(columnVariablesToAbstract);
1273 exitRates = exitRates.get() * actionExitRates;
1275 if (!action.transientEdgeAssignments.empty()) {
1276 for (
auto const& entry : action.transientEdgeAssignments) {
1277 auto transientEdgeAssignmentIt = transientEdgeAssignments.find(entry.first);
1278 if (transientEdgeAssignmentIt != transientEdgeAssignments.end()) {
1279 transientEdgeAssignmentIt->second *= entry.second / actionExitRates;
1281 transientEdgeAssignments.emplace(entry.first, entry.second / actionExitRates);
1286 }
else if (hasTransientEdgeAssignments) {
1288 for (
auto const& actionIndexPair : actions) {
1289 auto const& action = actionIndexPair.second.get();
1290 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments);
1294 storm::dd::Bdd<Type> newIllegalFragment = this->variables.manager->getBddZero();
1295 for (
auto const& actionIndexPair : actions) {
1296 auto componentIndex = actionIndexPair.first;
1297 auto const& action = actionIndexPair.second.get();
1299 if (guardDisjunction) {
1300 guardDisjunction.get() |= action.guard;
1303 lowestNondeterminismVariable = std::min(lowestNondeterminismVariable, action.getLowestLocalNondeterminismVariable());
1304 highestNondeterminismVariable = std::max(highestNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1306 if (action.isInputEnabled()) {
1308 transitions *= action.guard.ite(
1310 encodeIndex(0, action.getLowestLocalNondeterminismVariable(),
1311 action.getHighestLocalNondeterminismVariable() - action.getLowestLocalNondeterminismVariable(), this->variables) *
1312 subautomata[componentIndex].identity);
1314 transitions *= action.transitions;
1318 auto nondetVariables =
1319 std::set<storm::expressions::Variable>(this->variables.localNondeterminismVariables.begin() + action.getLowestLocalNondeterminismVariable(),
1320 this->variables.localNondeterminismVariables.begin() + action.getHighestLocalNondeterminismVariable());
1322 for (
auto const& entry : action.variableToWritingFragment) {
1323 storm::dd::Bdd<Type> guardedWritingFragment = inputEnabledGuard && entry.second;
1327 auto globalFragmentIt = globalVariableToWritingFragment.find(entry.first);
1328 if (globalFragmentIt != globalVariableToWritingFragment.end()) {
1331 globalFragmentIt->second &= guardedWritingFragment;
1333 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] && guardedWritingFragment.
existsAbstract(nondetVariables);
1334 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] |= guardedWritingFragment.
existsAbstract(nondetVariables);
1338 globalVariableToWritingFragment[entry.first] = guardedWritingFragment;
1339 globalVariableToWritingFragmentWithoutNondeterminism[entry.first] = guardedWritingFragment.
existsAbstract(nondetVariables);
1344 illegalFragment |= action.illegalFragment;
1349 for (
auto& entry : globalVariableToWritingFragment) {
1350 if (action.variableToWritingFragment.find(entry.first) == action.variableToWritingFragment.end() && !action.isInputEnabled()) {
1351 entry.second &= action.guard;
1355 if (!action.isInputEnabled()) {
1356 inputEnabledGuard &= action.guard;
1362 if (allActionsInputEnabled) {
1363 inputEnabledGuard &= guardDisjunction.get();
1364 transitions *= guardDisjunction.get().template toAdd<ValueType>();
1369 illegalFragment &= inputEnabledGuard;
1371 storm::dd::Add<Type, ValueType> transientEdgeAssignmentWeights;
1372 if (hasTransientEdgeAssignments) {
1373 transientEdgeAssignmentWeights = inputEnabledGuard.template toAdd<ValueType>();
1375 transientEdgeAssignmentWeights *= exitRates.get();
1378 for (
auto& entry : transientEdgeAssignments) {
1379 entry.second *= transientEdgeAssignmentWeights;
1383 return ActionDd(inputEnabledGuard, transitions * nonSynchronizingIdentity, transientEdgeAssignments,
1384 std::make_pair(lowestNondeterminismVariable, highestNondeterminismVariable), globalVariableToWritingFragment, illegalFragment);
1387 ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2, storm::dd::Add<Type, ValueType>
const& identity1,
1388 storm::dd::Add<Type, ValueType>
const& identity2) {
1390 STORM_LOG_TRACE(
"Multiplying identities to combine unsynchronized actions.");
1391 action1.transitions = action1.transitions * identity2;
1392 action2.transitions = action2.transitions * identity1;
1395 return combineUnsynchronizedActions(action1, action2);
1398 ActionDd combineUnsynchronizedActions(ActionDd action1, ActionDd action2) {
1399 return combineUnsynchronizedActions({action1, action2});
1402 ActionDd combineUnsynchronizedActions(std::vector<ActionDd> actions) {
1406 auto actionIt = actions.begin();
1407 ActionDd result(*actionIt);
1409 for (++actionIt; actionIt != actions.end(); ++actionIt) {
1410 result = ActionDd(result.guard || actionIt->guard, result.transitions + actionIt->transitions,
1411 joinTransientAssignmentMaps(result.transientEdgeAssignments, actionIt->transientEdgeAssignments),
1412 std::make_pair<uint64_t, uint64_t>(0, 0),
1413 joinVariableWritingFragmentMaps(result.variableToWritingFragment, actionIt->variableToWritingFragment),
1414 result.illegalFragment || actionIt->illegalFragment);
1420 uint_fast64_t lowestLocalNondeterminismVariable = actions.front().getLowestLocalNondeterminismVariable();
1421 uint_fast64_t highestLocalNondeterminismVariable = actions.front().getHighestLocalNondeterminismVariable();
1422 for (
auto const& action : actions) {
1423 STORM_LOG_ASSERT(action.getLowestLocalNondeterminismVariable() == lowestLocalNondeterminismVariable,
1424 "Mismatching lowest nondeterminism variable indices.");
1425 highestLocalNondeterminismVariable = std::max(highestLocalNondeterminismVariable, action.getHighestLocalNondeterminismVariable());
1429 for (
auto& action : actions) {
1430 storm::dd::Bdd<Type> nondeterminismEncodingBdd = this->variables.manager->getBddOne();
1431 for (uint_fast64_t i = action.getHighestLocalNondeterminismVariable(); i < highestLocalNondeterminismVariable; ++i) {
1432 nondeterminismEncodingBdd &= this->variables.manager->
getEncoding(this->variables.localNondeterminismVariables[i], 0);
1434 storm::dd::Add<Type, ValueType> nondeterminismEncoding = nondeterminismEncodingBdd.template toAdd<ValueType>();
1436 action.transitions *= nondeterminismEncoding;
1438 for (
auto& variableFragment : action.variableToWritingFragment) {
1439 variableFragment.second &= nondeterminismEncodingBdd;
1441 for (
auto& transientAssignment : action.transientEdgeAssignments) {
1442 transientAssignment.second *= nondeterminismEncoding;
1446 uint64_t numberOfLocalNondeterminismVariables =
static_cast<uint64_t
>(std::ceil(std::log2(actions.size())));
1447 storm::dd::Bdd<Type> guard = this->variables.manager->getBddZero();
1448 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
1449 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1450 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1451 storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
1453 for (uint64_t actionIndex = 0; actionIndex < actions.size(); ++actionIndex) {
1454 ActionDd& action = actions[actionIndex];
1456 guard |= action.guard;
1458 storm::dd::Add<Type, ValueType> nondeterminismEncoding =
1459 encodeIndex(actionIndex, highestLocalNondeterminismVariable, numberOfLocalNondeterminismVariables, this->variables);
1460 transitions += nondeterminismEncoding * action.transitions;
1462 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, action.transientEdgeAssignments, nondeterminismEncoding);
1464 storm::dd::Bdd<Type> nondeterminismEncodingBdd = nondeterminismEncoding.
toBdd();
1465 for (
auto& entry : action.variableToWritingFragment) {
1466 entry.second &= nondeterminismEncodingBdd;
1468 addToVariableWritingFragmentMap(variableToWritingFragment, action.variableToWritingFragment);
1469 illegalFragment |= action.illegalFragment;
1472 return ActionDd(guard, transitions, transientEdgeAssignments,
1473 std::make_pair(lowestLocalNondeterminismVariable, highestLocalNondeterminismVariable + numberOfLocalNondeterminismVariables),
1474 variableToWritingFragment, illegalFragment);
1476 STORM_LOG_THROW(
false, storm::exceptions::InvalidStateException,
"Illegal model type.");
1481 std::function<
void(storm::jani::Assignment
const&)>
const& callback) {
1482 auto transientVariableIt = this->transientVariables.begin();
1483 auto transientVariableIte = this->transientVariables.end();
1484 for (
auto const& assignment : transientAssignments) {
1485 while (transientVariableIt != transientVariableIte && *transientVariableIt < assignment.getExpressionVariable()) {
1486 ++transientVariableIt;
1488 if (transientVariableIt == transientVariableIte) {
1491 if (*transientVariableIt == assignment.getExpressionVariable()) {
1492 callback(assignment);
1493 ++transientVariableIt;
1498 EdgeDd buildEdgeDd(storm::jani::Automaton
const& automaton, storm::jani::Edge
const& edge) {
1503 storm::dd::Bdd<Type> guard = this->variables.rowExpressionAdapter->translateBooleanExpression(edge.
getGuard());
1504 storm::dd::Bdd<Type> rangedGuard = guard && this->variables.automatonToRangeMap.at(automaton.
getName()).toBdd();
1507 if (!rangedGuard.
isZero()) {
1509 std::vector<EdgeDestinationDd<Type, ValueType>> destinationDds;
1510 for (storm::jani::EdgeDestination
const& destination : edge.
getDestinations()) {
1513 STORM_LOG_WARN_COND(!destinationDds.back().transitions.isZero(),
"Destination does not have any effect.");
1517 storm::dd::Bdd<Type> sourceLocationBdd = this->variables.manager->getEncoding(
1519 guard = sourceLocationBdd && rangedGuard;
1522 std::set<storm::expressions::Variable> globalVariablesInSomeDestination;
1528 for (
auto const& edgeDestinationDd : destinationDds) {
1529 globalVariablesInSomeDestination.insert(edgeDestinationDd.writtenGlobalVariables.begin(), edgeDestinationDd.writtenGlobalVariables.end());
1532 globalVariablesInSomeDestination = this->variables.allGlobalVariables;
1536 for (
auto& destinationDd : destinationDds) {
1537 std::set<storm::expressions::Variable> missingIdentities;
1538 std::set_difference(globalVariablesInSomeDestination.begin(), globalVariablesInSomeDestination.end(),
1539 destinationDd.writtenGlobalVariables.begin(), destinationDd.writtenGlobalVariables.end(),
1540 std::inserter(missingIdentities, missingIdentities.begin()));
1542 for (
auto const& variable : missingIdentities) {
1544 destinationDd.transitions *= this->variables.variableToIdentityMap.at(variable);
1549 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
1550 for (
auto const& destinationDd : destinationDds) {
1551 transitions += destinationDd.transitions;
1555 storm::dd::Add<Type, ValueType> guardAdd = guard.template toAdd<ValueType>();
1556 transitions *= guardAdd;
1559 if (!globalVariablesInSomeDestination.empty()) {
1560 transitions *= this->variables.globalVariableRanges;
1564 bool isMarkovian =
false;
1565 boost::optional<storm::dd::Add<Type, ValueType>> exitRates;
1567 exitRates = this->variables.rowExpressionAdapter->translateExpression(edge.
getRate());
1568 transitions *= exitRates.get();
1573 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1574 if (!this->transientVariables.empty()) {
1576 &exitRates](storm::jani::Assignment
const& assignment) {
1577 auto newTransientEdgeAssignments = guardAdd * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1579 newTransientEdgeAssignments *= exitRates.get();
1585 return EdgeDd(isMarkovian, guard, transitions, transientEdgeAssignments, globalVariablesInSomeDestination);
1587 return EdgeDd(edge.
hasRate(), rangedGuard, rangedGuard.template toAdd<ValueType>(),
1588 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>(), std::set<storm::expressions::Variable>());
1592 EdgeDd combineMarkovianEdgesToSingleEdge(std::vector<EdgeDd>
const& edgeDds) {
1593 storm::dd::Bdd<Type> guard = this->variables.manager->getBddZero();
1594 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
1595 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1596 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> variableToWritingFragment;
1598 bool overlappingGuards =
false;
1599 for (
auto const& edge : edgeDds) {
1600 STORM_LOG_THROW(edge.isMarkovian, storm::exceptions::WrongFormatException,
"Can only combine Markovian edges.");
1602 if (!overlappingGuards) {
1603 overlappingGuards |= !(guard && edge.guard).
isZero();
1606 guard |= edge.guard;
1607 transitions += edge.transitions;
1608 variableToWritingFragment = joinVariableWritingFragmentMaps(variableToWritingFragment, edge.variableToWritingFragment);
1609 joinTransientAssignmentMapsInPlace(transientEdgeAssignments, edge.transientEdgeAssignments);
1613 STORM_LOG_THROW(!overlappingGuards || transientEdgeAssignments.empty(), storm::exceptions::NotSupportedException,
1614 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1616 return EdgeDd(
true, guard, transitions, transientEdgeAssignments, variableToWritingFragment);
1619 ActionDd buildActionDdForActionInstantiation(storm::jani::Automaton
const& automaton, ActionInstantiation
const& instantiation) {
1621 std::vector<EdgeDd> edgeDds;
1622 for (
auto const& edge : automaton.
getEdges()) {
1623 if (edge.
getActionIndex() == instantiation.actionIndex && edge.
hasRate() == instantiation.isMarkovian()) {
1624 EdgeDd result = buildEdgeDd(automaton, edge);
1625 edgeDds.emplace_back(result);
1630 uint64_t localNondeterminismVariableOffset = instantiation.localNondeterminismVariableOffset;
1631 if (!edgeDds.empty()) {
1634 return combineEdgesToActionDeterministic(edgeDds);
1636 return combineEdgesToActionDeterministic(edgeDds);
1638 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1640 if (instantiation.isMarkovian()) {
1641 return combineEdgesToActionDeterministic(edgeDds);
1643 return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset);
1646 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Cannot translate model of type " << modelType <<
".");
1649 return ActionDd(this->variables.manager->getBddZero(), this->variables.manager->template getAddZero<ValueType>(), {},
1650 std::make_pair<uint64_t, uint64_t>(0, 0), {}, this->variables.manager->getBddZero());
1654 void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments,
1655 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>
const& assignmentsToAdd) {
1656 for (
auto const& entry : assignmentsToAdd) {
1657 auto it = transientAssignments.find(entry.first);
1658 if (it != transientAssignments.end()) {
1659 it->second += entry.second;
1661 transientAssignments[entry.first] = entry.second;
1666 void addToTransientAssignmentMap(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& transientAssignments,
1667 storm::expressions::Variable
const& variable, storm::dd::Add<Type, ValueType>
const& assignmentToAdd) {
1668 auto it = transientAssignments.find(variable);
1669 if (it != transientAssignments.end()) {
1670 it->second += assignmentToAdd;
1672 transientAssignments[variable] = assignmentToAdd;
1676 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> joinTransientAssignmentMaps(
1677 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>
const& transientAssignments1,
1678 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>
const& transientAssignments2) {
1679 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> result = transientAssignments1;
1681 for (
auto const& entry : transientAssignments2) {
1682 auto resultIt = result.find(entry.first);
1683 if (resultIt != result.end()) {
1684 resultIt->second += entry.second;
1686 result.emplace(entry);
1693 void joinTransientAssignmentMapsInPlace(std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>& target,
1694 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>>
const& newTransientAssignments,
1695 boost::optional<storm::dd::Add<Type, ValueType>>
const& factor = boost::none) {
1696 for (
auto const& entry : newTransientAssignments) {
1697 auto targetIt = target.find(entry.first);
1698 if (targetIt != target.end()) {
1699 targetIt->second += factor ? factor.get() * entry.second : entry.second;
1701 target[entry.first] = factor ? factor.get() * entry.second : entry.second;
1706 ActionDd combineEdgesToActionDeterministic(std::vector<EdgeDd>
const& edgeDds) {
1707 storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero();
1708 storm::dd::Add<Type, ValueType> allTransitions = this->variables.manager->template getAddZero<ValueType>();
1709 storm::dd::Bdd<Type> temporary;
1711 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1712 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1713 bool overlappingGuards =
false;
1714 for (
auto const& edgeDd : edgeDds) {
1717 storm::exceptions::WrongFormatException,
"Unexpected edge type.");
1720 overlappingGuards = !(edgeDd.guard && allGuards).
isZero();
1725 "Guard of an edge in a DTMC overlaps with previous guards.");
1728 allGuards |= edgeDd.guard;
1729 allTransitions += edgeDd.transitions;
1734 addToTransientAssignmentMap(transientEdgeAssignments, edgeDd.transientEdgeAssignments);
1737 globalVariableToWritingFragment = joinVariableWritingFragmentMaps(globalVariableToWritingFragment, edgeDd.variableToWritingFragment);
1741 storm::exceptions::NotSupportedException,
1742 "Cannot have transient edge assignments when combining Markovian edges with overlapping guards.");
1744 return ActionDd(allGuards, allTransitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1745 this->variables.manager->getBddZero());
1748 void addToVariableWritingFragmentMap(std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>& globalVariableToWritingFragment,
1749 storm::expressions::Variable
const& variable, storm::dd::Bdd<Type>
const& partToAdd)
const {
1750 auto it = globalVariableToWritingFragment.find(variable);
1751 if (it != globalVariableToWritingFragment.end()) {
1752 it->second |= partToAdd;
1754 globalVariableToWritingFragment.emplace(variable, partToAdd);
1758 void addToVariableWritingFragmentMap(std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>& globalVariableToWritingFragment,
1759 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& partToAdd)
const {
1760 for (
auto const& entry : partToAdd) {
1761 addToVariableWritingFragmentMap(globalVariableToWritingFragment, entry.first, entry.second);
1765 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> joinVariableWritingFragmentMaps(
1766 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& globalVariableToWritingFragment1,
1767 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>>
const& globalVariableToWritingFragment2) {
1768 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> result = globalVariableToWritingFragment1;
1770 for (
auto const& entry : globalVariableToWritingFragment2) {
1771 auto resultIt = result.find(entry.first);
1772 if (resultIt != result.end()) {
1773 resultIt->second |= entry.second;
1775 result[entry.first] = entry.second;
1782 ActionDd combineEdgesBySummation(storm::dd::Bdd<Type>
const& guard, std::vector<EdgeDd>
const& edges) {
1783 storm::dd::Add<Type, ValueType> transitions = this->variables.manager->template getAddZero<ValueType>();
1784 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1785 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
1787 for (
auto const& edge : edges) {
1788 transitions += edge.transitions;
1789 for (
auto const& assignment : edge.transientEdgeAssignments) {
1790 addToTransientAssignmentMap(transientEdgeAssignments, assignment.first, assignment.second);
1792 for (
auto const& variableFragment : edge.variableToWritingFragment) {
1793 addToVariableWritingFragmentMap(globalVariableToWritingFragment, variableFragment.first, variableFragment.second);
1797 return ActionDd(guard, transitions, transientEdgeAssignments, std::make_pair<uint64_t, uint64_t>(0, 0), globalVariableToWritingFragment,
1798 this->variables.manager->getBddZero());
1801 ActionDd combineEdgesToActionNondeterministic(std::vector<EdgeDd>
const& edges, uint64_t localNondeterminismVariableOffset) {
1803 storm::dd::Bdd<Type> allGuards = this->variables.manager->getBddZero();
1804 storm::dd::Add<Type, uint_fast64_t> sumOfGuards = this->variables.manager->template getAddZero<uint_fast64_t>();
1805 for (
auto const& edge : edges) {
1807 sumOfGuards += edge.guard.template toAdd<uint_fast64_t>();
1808 allGuards |= edge.guard;
1810 uint_fast64_t maxChoices = sumOfGuards.
getMax();
1811 STORM_LOG_TRACE(
"Found " << maxChoices <<
" non-Markovian local choices.");
1814 if (maxChoices <= 1) {
1815 return combineEdgesBySummation(allGuards, edges);
1818 uint_fast64_t numberOfBinaryVariables =
static_cast<uint_fast64_t
>(std::ceil(std::log2(maxChoices)));
1820 storm::dd::Add<Type, ValueType> allEdges = this->variables.manager->template getAddZero<ValueType>();
1821 std::map<storm::expressions::Variable, storm::dd::Bdd<Type>> globalVariableToWritingFragment;
1822 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientAssignments;
1824 storm::dd::Bdd<Type> equalsNumberOfChoicesDd;
1825 std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, this->variables.manager->template getAddZero<ValueType>());
1826 std::vector<storm::dd::Bdd<Type>> remainingDds(maxChoices, this->variables.manager->getBddZero());
1827 std::vector<std::pair<storm::dd::Bdd<Type>, storm::dd::Add<Type, ValueType>>> indicesEncodedWithLocalNondeterminismVariables;
1828 for (uint64_t j = 0; j < maxChoices; ++j) {
1829 storm::dd::Add<Type, ValueType> indexEncoding =
encodeIndex(j, localNondeterminismVariableOffset, numberOfBinaryVariables, this->variables);
1830 indicesEncodedWithLocalNondeterminismVariables.push_back(std::make_pair(indexEncoding.
toBdd(), indexEncoding));
1833 for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
1835 equalsNumberOfChoicesDd = sumOfGuards.
equals(this->variables.manager->getConstant(currentChoices));
1838 if (equalsNumberOfChoicesDd.
isZero()) {
1843 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1844 choiceDds[j] = this->variables.manager->template getAddZero<ValueType>();
1845 remainingDds[j] = equalsNumberOfChoicesDd;
1848 for (std::size_t j = 0; j < edges.size(); ++j) {
1849 EdgeDd
const& currentEdge = edges[j];
1853 storm::dd::Bdd<Type> guardChoicesIntersection = currentEdge.guard && equalsNumberOfChoicesDd;
1856 if (guardChoicesIntersection.
isZero()) {
1861 for (uint_fast64_t k = 0; k < currentChoices; ++k) {
1863 storm::dd::Bdd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k];
1866 if (!remainingGuardChoicesIntersection.
isZero()) {
1868 remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection;
1871 choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * currentEdge.transitions;
1874 for (
auto const& transientAssignment : currentEdge.transientEdgeAssignments) {
1875 addToTransientAssignmentMap(transientAssignments, transientAssignment.first,
1876 remainingGuardChoicesIntersection.template toAdd<ValueType>() * transientAssignment.second *
1877 indicesEncodedWithLocalNondeterminismVariables[k].second);
1881 for (
auto const& variableFragment : currentEdge.variableToWritingFragment) {
1882 addToVariableWritingFragmentMap(
1883 globalVariableToWritingFragment, variableFragment.first,
1884 remainingGuardChoicesIntersection && variableFragment.second && indicesEncodedWithLocalNondeterminismVariables[k].first);
1889 guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection;
1892 if (guardChoicesIntersection.
isZero()) {
1899 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1900 allEdges += indicesEncodedWithLocalNondeterminismVariables[j].second * choiceDds[j];
1904 sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).
template toAdd<uint_fast64_t>();
1907 return ActionDd(allGuards, allEdges, transientAssignments,
1908 std::make_pair(localNondeterminismVariableOffset, localNondeterminismVariableOffset + numberOfBinaryVariables),
1909 globalVariableToWritingFragment, this->variables.manager->getBddZero());
1913 AutomatonDd buildAutomatonDd(std::string
const& automatonName, ActionInstantiations
const& actionInstantiations,
1914 std::set<uint64_t>
const& inputEnabledActionIndices,
bool isTopLevelAutomaton) {
1915 STORM_LOG_TRACE(
"Building DD for automaton '" << automatonName <<
"'.");
1916 AutomatonDd result(this->variables.automatonToIdentityMap.at(automatonName));
1919 storm::dd::Bdd<Type> nonMarkovianActionGuards = this->variables.manager->getBddZero();
1921 storm::jani::Automaton
const& automaton = this->model.getAutomaton(automatonName);
1922 for (
auto const& actionInstantiation : actionInstantiations) {
1923 uint64_t actionIndex = actionInstantiation.first;
1927 bool inputEnabled =
false;
1928 if (inputEnabledActionIndices.find(actionIndex) != inputEnabledActionIndices.end()) {
1929 inputEnabled =
true;
1931 for (
auto const& instantiation : actionInstantiation.second) {
1932 STORM_LOG_TRACE(
"Building " << (instantiation.isMarkovian() ?
"(Markovian) " :
"")
1933 << (actionInformation.
getActionName(actionIndex).empty() ?
"silent " :
"") <<
"action "
1935 <<
"from offset " << instantiation.localNondeterminismVariableOffset <<
".");
1936 ActionDd actionDd = buildActionDdForActionInstantiation(automaton, instantiation);
1938 actionDd.setIsInputEnabled();
1940 if (applyMaximumProgress && isTopLevelAutomaton && !instantiation.isMarkovian()) {
1941 nonMarkovianActionGuards |= actionDd.guard;
1943 STORM_LOG_TRACE(
"Used local nondeterminism variables are " << actionDd.getLowestLocalNondeterminismVariable() <<
" to "
1944 << actionDd.getHighestLocalNondeterminismVariable() <<
".");
1945 result.actions[ActionIdentification(actionIndex, instantiation.synchronizationVectorIndex, instantiation.isMarkovian())] = actionDd;
1946 result.extendLocalNondeterminismVariables(actionDd.getLocalNondeterminismVariables());
1950 if (applyMaximumProgress && isTopLevelAutomaton) {
1952 result.actions[silentMarkovianActionIdentification].conjunctGuardWith(!nonMarkovianActionGuards);
1955 for (uint64_t locationIndex = 0; locationIndex < automaton.
getNumberOfLocations(); ++locationIndex) {
1956 auto const& location = automaton.
getLocation(locationIndex);
1957 performTransientAssignments(
1958 location.getAssignments().getTransientAssignments(), [
this, &automatonName, locationIndex, &result](storm::jani::Assignment
const& assignment) {
1959 storm::dd::Add<Type, ValueType> assignedValues =
1960 this->variables.manager->getEncoding(this->variables.automatonToLocationDdVariableMap.at(automatonName).first, locationIndex)
1961 .template toAdd<ValueType>() *
1962 this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression());
1964 auto it = result.transientLocationAssignments.find(assignment.getExpressionVariable());
1965 if (it != result.transientLocationAssignments.end()) {
1966 it->second += assignedValues;
1968 result.transientLocationAssignments[assignment.getExpressionVariable()] = assignedValues;
1976 void addMissingGlobalVariableIdentities(ActionDd& action) {
1978 storm::dd::Add<Type, ValueType> missingIdentities = this->variables.manager->template getAddOne<ValueType>();
1980 for (
auto const& variable : this->variables.allGlobalVariables) {
1981 auto it = action.variableToWritingFragment.find(variable);
1982 if (it != action.variableToWritingFragment.end()) {
1983 missingIdentities *=
1984 (it->second).
ite(this->variables.manager->template getAddOne<ValueType>(), this->variables.variableToIdentityMap.at(variable));
1986 missingIdentities *= this->variables.variableToIdentityMap.at(variable);
1990 action.transitions *= missingIdentities;
1996 auto modelType = this->model.getModelType();
2000 storm::dd::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>();
2001 storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
2005 uint64_t numberOfUsedNondeterminismVariables = automaton.getHighestLocalNondeterminismVariable();
2006 STORM_LOG_TRACE(
"Building system from composed automaton; number of used nondeterminism variables is " << numberOfUsedNondeterminismVariables
2010 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2011 std::unordered_set<ActionIdentification, ActionIdentificationHash> containedActions;
2012 for (
auto& action : automaton.actions) {
2013 STORM_LOG_TRACE(
"Treating action with index " << action.first.actionIndex << (action.first.isMarkovian() ?
" (Markovian)" :
"") <<
".");
2015 uint64_t actionIndex = action.first.actionIndex;
2016 bool markovian = action.first.isMarkovian();
2017 ActionIdentification identificationWithoutSynchVector(actionIndex, markovian);
2019 STORM_LOG_THROW(containedActions.find(identificationWithoutSynchVector) == containedActions.end(), storm::exceptions::WrongFormatException,
2020 "Duplicate action " << actionInformation.
getActionName(actionIndex) <<
".");
2021 containedActions.insert(identificationWithoutSynchVector);
2022 illegalFragment |= action.second.illegalFragment;
2023 addMissingGlobalVariableIdentities(action.second);
2024 storm::dd::Add<Type, ValueType> actionEncoding =
2028 storm::dd::Add<Type, ValueType> missingNondeterminismEncoding =
2029 encodeIndex(0, action.second.getHighestLocalNondeterminismVariable(),
2030 numberOfUsedNondeterminismVariables - action.second.getHighestLocalNondeterminismVariable(), this->variables);
2031 storm::dd::Add<Type, ValueType> extendedTransitions = actionEncoding * missingNondeterminismEncoding * action.second.transitions;
2032 for (
auto const& transientAssignment : action.second.transientEdgeAssignments) {
2033 addToTransientAssignmentMap(transientEdgeAssignments, transientAssignment.first,
2034 actionEncoding * missingNondeterminismEncoding * transientAssignment.second);
2037 result += extendedTransitions;
2041 numberOfUsedNondeterminismVariables);
2045 storm::dd::Add<Type, ValueType> result = this->variables.manager->template getAddZero<ValueType>();
2046 storm::dd::Bdd<Type> illegalFragment = this->variables.manager->getBddZero();
2047 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> transientEdgeAssignments;
2048 std::unordered_set<uint64_t> actionIndices;
2049 for (
auto& action : automaton.actions) {
2050 STORM_LOG_THROW(actionIndices.find(action.first.actionIndex) == actionIndices.end(), storm::exceptions::WrongFormatException,
2051 "Duplication action " << actionInformation.
getActionName(action.first.actionIndex) <<
".");
2052 actionIndices.insert(action.first.actionIndex);
2053 illegalFragment |= action.second.illegalFragment;
2054 addMissingGlobalVariableIdentities(action.second);
2055 addToTransientAssignmentMap(transientEdgeAssignments, action.second.transientEdgeAssignments);
2056 result += action.second.transitions;
2061 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Model type '" << this->model.getModelType() <<
"' not supported.");