1636 lines
96 KiB

#include "src/builder/DdPrismModelBuilder.h"
#include "src/storage/dd/CuddDd.h"
#include "src/storage/dd/CuddDdManager.h"
#include "src/settings/SettingsManager.h"
#include "src/exceptions/InvalidStateException.h"
#include "src/utility/prism.h"
#include "src/utility/math.h"
namespace storm {
namespace builder {
template <storm::dd::DdType Type>
DdPrismModelBuilder<Type>::Options::Options() : buildRewards(false), rewardModelName(), constantDefinitions() {
// Intentionally left empty.
}
template <storm::dd::DdType Type>
DdPrismModelBuilder<Type>::Options::Options(storm::logic::Formula const& formula) : buildRewards(formula.containsRewardOperator()), rewardModelName(), constantDefinitions(), labelsToBuild(std::set<std::string>()), expressionLabels(std::vector<storm::expressions::Expression>()) {
// Extract all the labels used in the formula.
std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>> atomicLabelFormulas = formula.getAtomicLabelFormulas();
for (auto const& formula : atomicLabelFormulas) {
labelsToBuild.get().insert(formula.get()->getLabel());
}
// Extract all the expressions used in the formula.
std::vector<std::shared_ptr<storm::logic::AtomicExpressionFormula const>> atomicExpressionFormulas = formula.getAtomicExpressionFormulas();
for (auto const& formula : atomicExpressionFormulas) {
expressionLabels.get().push_back(formula.get()->getExpression());
}
}
template <storm::dd::DdType Type>
void DdPrismModelBuilder<Type>::Options::addConstantDefinitionsFromString(storm::prism::Program const& program, std::string const& constantDefinitionString) {
std::map<storm::expressions::Variable, storm::expressions::Expression> newConstantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString);
// If there is at least one constant that is defined, and the constant definition map does not yet exist,
// we need to create it.
if (!constantDefinitions && !newConstantDefinitions.empty()) {
constantDefinitions = std::map<storm::expressions::Variable, storm::expressions::Expression>();
}
// Now insert all the entries that need to be defined.
for (auto const& entry : newConstantDefinitions) {
constantDefinitions.get().insert(entry);
}
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::createUpdateDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Update const& update) {
storm::dd::Dd<Type> updateDd = generationInfo.manager->getOne();
// Iterate over all assignments (boolean and integer) and build the DD for it.
std::vector<storm::prism::Assignment> assignments = update.getAssignments();
std::set<storm::expressions::Variable> assignedVariables;
for (auto const& assignment : assignments) {
// Record the variable as being written.
STORM_LOG_TRACE("Assigning to variable " << generationInfo.variableToRowMetaVariableMap.at(assignment.getVariable()).getName());
assignedVariables.insert(generationInfo.variableToRowMetaVariableMap.at(assignment.getVariable()));
// Translate the written variable.
auto const& primedMetaVariable = generationInfo.variableToColumnMetaVariableMap.at(assignment.getVariable());
storm::dd::Dd<Type> writtenVariable = generationInfo.manager->getIdentity(primedMetaVariable);
// Translate the expression that is being assigned.
storm::dd::Dd<Type> updateExpression = generationInfo.rowExpressionAdapter->translateExpression(assignment.getExpression());
// Combine the update expression with the guard.
storm::dd::Dd<Type> result = updateExpression * guard;
// Combine the variable and the assigned expression.
result = result.equals(writtenVariable);
result *= guard;
// Restrict the transitions to the range of the written variable.
result = result * generationInfo.manager->getRange(primedMetaVariable);
updateDd *= result;
}
// FIXME: global boolean variables cause problems. They cannot be added here, because then synchronization goes wrong.
// for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalBooleanVariables().size(); ++i) {
// storm::prism::BooleanVariable const& booleanVariable = generationInfo.program.getGlobalBooleanVariables().at(i);
// if (update.getAssignmentMapping().find(booleanVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(booleanVariable.getName());
// }
// }
//
// // All unused global integer variables do not change
// for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalIntegerVariables().size(); ++i) {
// storm::prism::IntegerVariable const& integerVariable = generationInfo.program.getGlobalIntegerVariables().at(i);
// if (update.getAssignmentMapping().find(integerVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(integerVariable.getName());
// }
// }
// All unassigned boolean variables need to keep their value.
for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) {
storm::expressions::Variable const& metaVariable = generationInfo.variableToRowMetaVariableMap.at(booleanVariable.getExpressionVariable());
if (assignedVariables.find(metaVariable) == assignedVariables.end()) {
STORM_LOG_TRACE("Multiplying identity of variable " << booleanVariable.getName());
updateDd *= generationInfo.variableToIdentityMap.at(booleanVariable.getExpressionVariable());
}
}
// All unassigned integer variables need to keep their value.
for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) {
storm::expressions::Variable const& metaVariable = generationInfo.variableToRowMetaVariableMap.at(integerVariable.getExpressionVariable());
if (assignedVariables.find(metaVariable) == assignedVariables.end()) {
STORM_LOG_TRACE("Multiplying identity of variable " << integerVariable.getName());
updateDd *= generationInfo.variableToIdentityMap.at(integerVariable.getExpressionVariable());
}
}
return updateDd;
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::createCommandDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::prism::Command const& command) {
STORM_LOG_TRACE("Translating guard " << command.getGuardExpression());
storm::dd::Dd<Type> guardDd = generationInfo.rowExpressionAdapter->translateExpression(command.getGuardExpression());
STORM_LOG_WARN_COND(!guardDd.isZero(), "The guard '" << command.getGuardExpression() << "' is unsatisfiable.");
if (!guardDd.isZero()) {
storm::dd::Dd<Type> commandDd = generationInfo.manager->getZero();
for (storm::prism::Update const& update : command.getUpdates()) {
storm::dd::Dd<Type> updateDd = createUpdateDecisionDiagram(generationInfo, module, guardDd, update);
STORM_LOG_WARN_COND(!updateDd.isZero(), "Update '" << update << "' does not have any effect.");
storm::dd::Dd<Type> probabilityDd = generationInfo.rowExpressionAdapter->translateExpression(update.getLikelihoodExpression());
updateDd *= probabilityDd;
commandDd += updateDd;
}
guardDd.exportToDot(module.getName() + "_cmd_" + std::to_string(command.getGlobalIndex()) + "_grd.dot");
commandDd.exportToDot(module.getName() + "_cmd_" + std::to_string(command.getGlobalIndex()) + ".dot");
return ActionDecisionDiagram(guardDd, guardDd * commandDd);
} else {
return ActionDecisionDiagram(*generationInfo.manager);
}
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::createActionDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, boost::optional<uint_fast64_t> synchronizationActionIndex, uint_fast64_t nondeterminismVariableOffset) {
std::vector<ActionDecisionDiagram> commandDds;
for (storm::prism::Command const& command : module.getCommands()) {
// Determine whether the command is relevant for the selected action.
bool relevant = (!synchronizationActionIndex && !command.isLabeled()) || (synchronizationActionIndex && command.getActionIndex() == synchronizationActionIndex.get());
if (!relevant) {
continue;
}
// At this point, the command is known to be relevant for the action.
commandDds.push_back(createCommandDecisionDiagram(generationInfo, module, command));
}
ActionDecisionDiagram result(*generationInfo.manager);
if (!commandDds.empty()) {
switch (generationInfo.program.getModelType()){
case storm::prism::Program::ModelType::DTMC:
result = combineCommandsToActionDTMC(generationInfo, commandDds);
break;
case storm::prism::Program::ModelType::MDP:
result = combineCommandsToActionMDP(generationInfo, commandDds, nondeterminismVariableOffset);
break;
default:
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type.");
}
}
return result;
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::combineCommandsToActionDTMC(GenerationInformation& generationInfo, std::vector<ActionDecisionDiagram> const& commandDds) {
storm::dd::Dd<Type> allGuards = generationInfo.manager->getZero();
storm::dd::Dd<Type> allCommands = generationInfo.manager->getZero();
storm::dd::Dd<Type> temporary;
for (auto const& commandDd : commandDds) {
// Check for overlapping guards.
temporary = commandDd.guardDd * allGuards;
STORM_LOG_WARN_COND(temporary.isZero(), "Guard of a command overlaps with previous guards.");
allGuards += commandDd.guardDd;
allCommands += commandDd.guardDd * commandDd.transitionsDd;
}
return ActionDecisionDiagram(allGuards, allCommands);
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::encodeChoice(GenerationInformation& generationInfo, uint_fast64_t nondeterminismVariableOffset, uint_fast64_t numberOfBinaryVariables, int_fast64_t value) {
storm::dd::Dd<Type> result = generationInfo.manager->getOne();
std::map<storm::expressions::Variable, int_fast64_t> metaVariableNameToValueMap;
for (uint_fast64_t i = nondeterminismVariableOffset; i < nondeterminismVariableOffset + numberOfBinaryVariables; ++i) {
if (value & (1ull << (numberOfBinaryVariables - i - 1))) {
metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 1);
}
else {
metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 0);
}
}
result.setValue(metaVariableNameToValueMap, 1);
return result;
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::combineCommandsToActionMDP(GenerationInformation& generationInfo, std::vector<ActionDecisionDiagram> const& commandDds, uint_fast64_t nondeterminismVariableOffset) {
storm::dd::Dd<Type> allGuards = generationInfo.manager->getZero();
storm::dd::Dd<Type> allCommands = generationInfo.manager->getZero();
// Sum all guards, so we can read off the maximal number of nondeterministic choices in any given state.
storm::dd::Dd<Type> sumOfGuards = generationInfo.manager->getZero();
for (auto const& commandDd : commandDds) {
sumOfGuards += commandDd.guardDd;
allGuards = allGuards || commandDd.guardDd;
}
uint_fast64_t maxChoices = static_cast<uint_fast64_t>(sumOfGuards.getMax());
// Depending on the maximal number of nondeterminstic choices, we need to use some variables to encode the nondeterminism.
if (maxChoices == 0) {
return ActionDecisionDiagram(*generationInfo.manager);
} else if (maxChoices == 1) {
// Sum up all commands.
for (auto const& commandDd : commandDds) {
// FIXME: necessary to multiply with guard again?
allCommands += commandDd.guardDd * commandDd.transitionsDd;
}
return ActionDecisionDiagram(sumOfGuards, allCommands);
} else {
// Calculate number of required variables to encode the nondeterminism.
uint_fast64_t numberOfBinaryVariables = static_cast<uint_fast64_t>(std::ceil(storm::utility::math::log2(maxChoices)));
storm::dd::Dd<Type> equalsNumberOfChoicesDd = generationInfo.manager->getZero();
std::vector<storm::dd::Dd<Type>> choiceDds(maxChoices, generationInfo.manager->getZero());
std::vector<storm::dd::Dd<Type>> remainingDds(maxChoices, generationInfo.manager->getZero());
for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
// Determine the set of states with exactly currentChoices choices.
equalsNumberOfChoicesDd = sumOfGuards.equals(generationInfo.manager->getConstant(static_cast<double>(currentChoices)));
// If there is no such state, continue with the next possible number of choices.
if (equalsNumberOfChoicesDd.isZero()) {
continue;
}
// Reset the previously used intermediate storage.
for (uint_fast64_t j = 0; j < currentChoices; ++j) {
choiceDds[j] = generationInfo.manager->getZero();
remainingDds[j] = equalsNumberOfChoicesDd;
}
for (std::size_t j = 0; j < commandDds.size(); ++j) {
// Check if command guard overlaps with equalsNumberOfChoicesDd. That is, there are states with exactly currentChoices
// choices such that one outgoing choice is given by the j-th command.
storm::dd::Dd<Type> guardChoicesIntersection = commandDds[j].guardDd && equalsNumberOfChoicesDd;
// If there is no such state, continue with the next command.
if (guardChoicesIntersection.isZero()) {
continue;
}
// Split the currentChoices nondeterministic choices.
for (uint_fast64_t k = 0; k < currentChoices; ++k) {
// Calculate the overlapping part of command guard and the remaining DD.
storm::dd::Dd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k];
// Check if we can add some overlapping parts to the current index
if (!remainingGuardChoicesIntersection.isZero()) {
// Remove overlapping parts from the remaining DD.
remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection;
// Combine the overlapping part of the guard with command updates and add it to the resulting DD.
choiceDds[k] += remainingGuardChoicesIntersection * commandDds[j].transitionsDd;
}
// Remove overlapping parts from the command guard DD
guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection;
// If the guard DD has become equivalent to false, we can stop here.
if (guardChoicesIntersection.isZero()) {
break;
}
}
}
// Add the meta variables that encode the nondeterminisim to the different choices.
for (uint_fast64_t j = 0; j < currentChoices; ++j) {
allCommands += encodeChoice(generationInfo, nondeterminismVariableOffset, numberOfBinaryVariables, j) * choiceDds[j];
}
// Delete currentChoices out of overlapping DD
sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd);
}
return ActionDecisionDiagram(allGuards, allCommands, nondeterminismVariableOffset + numberOfBinaryVariables);
}
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::combineSynchronizingActions(GenerationInformation const& generationInfo, ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2) {
return ActionDecisionDiagram(action1.guardDd * action2.guardDd, action1.transitionsDd * action2.transitionsDd, std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables));
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ActionDecisionDiagram DdPrismModelBuilder<Type>::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2, storm::dd::Dd<Type> const& identityDd1, storm::dd::Dd<Type> const& identityDd2) {
storm::dd::Dd<Type> action1Extended = action1.transitionsDd * identityDd2;
storm::dd::Dd<Type> action2Extended = action2.transitionsDd * identityDd1;
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
return ActionDecisionDiagram(action1.guardDd + action2.guardDd, action1Extended + action2Extended, 0);
} else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
if (action1.transitionsDd.isZero()) {
return ActionDecisionDiagram(action2.guardDd, action2Extended, action2.numberOfUsedNondeterminismVariables);
} else if (action2.transitionsDd.isZero()) {
return ActionDecisionDiagram(action1.guardDd, action1Extended, action1.numberOfUsedNondeterminismVariables);
}
// Bring both choices to the same number of variables that encode the nondeterminism.
uint_fast64_t numberOfUsedNondeterminismVariables = std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables);
if (action1.numberOfUsedNondeterminismVariables > action2.numberOfUsedNondeterminismVariables) {
storm::dd::Dd<Type> nondeterminisimEncoding = generationInfo.manager->getOne();
for (uint_fast64_t i = action2.numberOfUsedNondeterminismVariables + 1; i <= action1.numberOfUsedNondeterminismVariables; ++i) {
nondeterminisimEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0);
}
action2Extended *= nondeterminisimEncoding;
} else if (action2.numberOfUsedNondeterminismVariables > action1.numberOfUsedNondeterminismVariables) {
storm::dd::Dd<Type> nondeterminisimEncoding = generationInfo.manager->getOne();
for (uint_fast64_t i = action1.numberOfUsedNondeterminismVariables + 1; i <= action2.numberOfUsedNondeterminismVariables; ++i) {
nondeterminisimEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0);
}
action1Extended *= nondeterminisimEncoding;
}
// Add a new variable that resolves the nondeterminism between the two choices.
storm::dd::Dd<Type> combinedTransitions = generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables + 1], 1).ite(action2Extended, action1Extended);
return ActionDecisionDiagram(action1.guardDd || action2.guardDd, combinedTransitions, numberOfUsedNondeterminismVariables + 1);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
}
}
template <storm::dd::DdType Type>
typename DdPrismModelBuilder<Type>::ModuleDecisionDiagram DdPrismModelBuilder<Type>::createModuleDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap) {
// Start by creating the action DD for the independent action.
ActionDecisionDiagram independentActionDd = createActionDecisionDiagram(generationInfo, module, boost::optional<uint_fast64_t>(), 0);
// Create module DD for all synchronizing actions of the module.
std::map<uint_fast64_t, ActionDecisionDiagram> actionIndexToDdMap;
for (auto const& actionIndex : module.getActionIndices()) {
STORM_LOG_TRACE("Creating DD for action '" << actionIndex << "'.");
actionIndexToDdMap.emplace(actionIndex, createActionDecisionDiagram(generationInfo, module, actionIndex, synchronizingActionToOffsetMap.at(actionIndex)));
}
return ModuleDecisionDiagram(independentActionDd, actionIndexToDdMap, generationInfo.moduleToIdentityMap.at(module.getName()));
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::createSystemFromModule(GenerationInformation& generationInfo, ModuleDecisionDiagram const& module) {
// If the model is an MDP, we need to encode the nondeterminism using additional variables.
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
storm::dd::Dd<Type> result = generationInfo.manager->getZero();
// First, determine the maximal variable index that is used.
uint_fast64_t numberOfUsedNondeterminismVariables = module.independentAction.numberOfUsedNondeterminismVariables;
for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, synchronizingAction.second.numberOfUsedNondeterminismVariables);
}
// Now make all actions use the same amount of nondeterminism variables.
// Add variables to independent action DD.
storm::dd::Dd<Type> nondeterminismEncoding = generationInfo.manager->getOne();
for (uint_fast64_t i = module.independentAction.numberOfUsedNondeterminismVariables + 1; i <= numberOfUsedNondeterminismVariables; ++i) {
nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0);
}
result = module.independentAction.transitionsDd * nondeterminismEncoding;
// Add variables to synchronized action DDs.
std::map<uint_fast64_t, storm::dd::Dd<Type>> synchronizingActionToDdMap;
for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
nondeterminismEncoding = generationInfo.manager->getOne();
for (uint_fast64_t i = synchronizingAction.second.numberOfUsedNondeterminismVariables + 1; i <= numberOfUsedNondeterminismVariables; ++i) {
nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0);
}
synchronizingActionToDdMap.emplace(synchronizingAction.first, synchronizingAction.second.transitionsDd * nondeterminismEncoding);
}
// Add variables for synchronization.
storm::dd::Dd<Type> synchronization = generationInfo.manager->getOne();
for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) {
synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0);
}
result *= synchronization;
for (auto& synchronizingAction : synchronizingActionToDdMap) {
synchronization = generationInfo.manager->getOne();
for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) {
if (i == synchronizingAction.first) {
synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 1);
} else {
synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0);
}
}
synchronizingAction.second *= synchronization;
}
// Now, we can simply add all synchronizing actions to the result.
for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
result += synchronizingAction.second.transitionsDd;
}
return result;
} else {
// Simply add all actions.
storm::dd::Dd<Type> result = module.independentAction.transitionsDd;
for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
result += synchronizingAction.second.transitionsDd;
}
return result;
}
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::createSystemDecisionDiagram(GenerationInformation& generationInfo) {
// Create the initial offset mapping.
std::map<uint_fast64_t, uint_fast64_t> synchronizingActionToOffsetMap;
for (auto const& actionIndex : generationInfo.program.getActionIndices()) {
synchronizingActionToOffsetMap[actionIndex] = 0;
}
// Start by creating DDs for the first module.
STORM_LOG_TRACE("Translating (first) module '" << generationInfo.program.getModule(0).getName() << "'.");
ModuleDecisionDiagram system = createModuleDecisionDiagram(generationInfo, generationInfo.program.getModule(0), synchronizingActionToOffsetMap);
// No translate module by module and combine it with the system created thus far.
for (uint_fast64_t i = 1; i < generationInfo.program.getNumberOfModules(); ++i) {
storm::prism::Module const& currentModule = generationInfo.program.getModule(i);
STORM_LOG_TRACE("Translating module '" << currentModule.getName() << "'.");
// Update the offset index.
for (auto const& actionIndex : generationInfo.program.getActionIndices()) {
if (system.hasSynchronizingAction(actionIndex)) {
synchronizingActionToOffsetMap[actionIndex] = system.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables;
}
}
ModuleDecisionDiagram nextModule = createModuleDecisionDiagram(generationInfo, currentModule, synchronizingActionToOffsetMap);
// Combine the non-synchronizing action.
system.independentAction = combineUnsynchronizedActions(generationInfo, system.independentAction, nextModule.independentAction, system.identity, nextModule.identity);
// Combine synchronizing actions.
for (auto const& actionIndex : currentModule.getActionIndices()) {
std::cout << "treating action index " << actionIndex << std::endl;
if (system.hasSynchronizingAction(actionIndex)) {
system.synchronizingActionToDecisionDiagramMap[actionIndex] = combineSynchronizingActions(generationInfo, system.synchronizingActionToDecisionDiagramMap[actionIndex], nextModule.synchronizingActionToDecisionDiagramMap[actionIndex]);
} else {
system.synchronizingActionToDecisionDiagramMap[actionIndex] = combineUnsynchronizedActions(generationInfo, ActionDecisionDiagram(*generationInfo.manager), nextModule.synchronizingActionToDecisionDiagramMap[actionIndex], system.identity, nextModule.identity);
}
}
// Combine identity matrices.
system.identity = system.identity * nextModule.identity;
}
storm::dd::Dd<Type> result = createSystemFromModule(generationInfo, system);
// For DTMCs, we normalize each row to 1 (to account for non-determinism).
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
result = result / result.sumAbstract(generationInfo.columnMetaVariables);
}
return result;
}
template <storm::dd::DdType Type>
void DdPrismModelBuilder<Type>::translateProgram(storm::prism::Program const& program, Options const& options) {
// There might be nondeterministic variables. In that case the program must be prepared before translating.
storm::prism::Program preparedProgram;
if (options.constantDefinitions) {
preparedProgram = program.defineUndefinedConstants(options.constantDefinitions.get());
} else {
preparedProgram = program;
}
preparedProgram = preparedProgram.substituteConstants();
std::cout << "translated prog: " << preparedProgram << std::endl;
// Start by initializing the structure used for storing all information needed during the model generation.
// In particular, this creates the meta variables used to encode the model.
GenerationInformation generationInfo(preparedProgram);
auto clock = std::chrono::high_resolution_clock::now();
storm::dd::Dd<Type> transitionMatrix = createSystemDecisionDiagram(generationInfo);
std::cout << "Built transition matrix in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
transitionMatrix.exportToDot("trans.dot");
std::cout << "num transitions: " << transitionMatrix.getNonZeroCount() << std::endl;
storm::dd::Dd<Type> initialStates = createInitialStatesDecisionDiagram(generationInfo);
std::cout << "initial states: " << initialStates.getNonZeroCount() << std::endl;
storm::dd::Dd<Type> reachableStates = computeReachableStates(generationInfo, initialStates, transitionMatrix);
std::cout << "reachable states: " << reachableStates.getNonZeroCount() << std::endl;
exit(-1);
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) {
storm::dd::Dd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialConstruct().getInitialStatesExpression());
for (auto const& metaVariable : generationInfo.rowMetaVariables) {
initialStates *= generationInfo.manager->getRange(metaVariable);
}
return initialStates;
}
template <storm::dd::DdType Type>
storm::dd::Dd<Type> DdPrismModelBuilder<Type>::computeReachableStates(GenerationInformation& generationInfo, storm::dd::Dd<Type> const& initialStates, storm::dd::Dd<Type> const& transitions) {
storm::dd::Dd<Type> reachableStatesBdd = initialStates.notZero();
// If the model is an MDP, we can abstract from the variables encoding the nondeterminism in the model.
storm::dd::Dd<Type> transitionBdd = transitions.notZero();
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
std::set<storm::expressions::Variable> abstractVariables;
abstractVariables.insert(generationInfo.synchronizationMetaVariables.begin(), generationInfo.synchronizationMetaVariables.end());
abstractVariables.insert(generationInfo.nondeterminismMetaVariables.begin(), generationInfo.nondeterminismMetaVariables.end());
transitionBdd = transitionBdd.existsAbstract(abstractVariables);
}
transitionBdd.exportToDot("trans.dot");
reachableStatesBdd.exportToDot("reach.dot");
// Perform the BFS to discover all reachable states.
bool changed = true;
uint_fast64_t iteration = 0;
do {
STORM_LOG_TRACE("Iteration " << iteration << " of computing reachable states.");
changed = false;
storm::dd::Dd<Type> tmp = reachableStatesBdd * transitionBdd;
tmp = tmp.existsAbstract(generationInfo.rowMetaVariables);
tmp.swapVariables(generationInfo.rowColumnMetaVariablePairs);
storm::dd::Dd<Type> newReachableStates = tmp * (!reachableStatesBdd);
// Check whether new states were indeed discovered.
if (!newReachableStates.isZero()) {
changed = true;
}
reachableStatesBdd += newReachableStates;
++iteration;
} while (changed);
return reachableStatesBdd;
}
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createSystemDecisionDiagramm(GenerationInformation & generationInfo){
//
// uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
//
// // System DDs
// SystemComponentDecisionDiagram<Type> systemDds(0);
// SystemComponentDecisionDiagram<Type> systemDds1(0);
// SystemComponentDecisionDiagram<Type> systemDds2(0);
//
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
//
// // Initialize usedNondetVariablesVector
// // TODO: Formulate simpler.
// std::vector<uint_fast64_t> usedNondetVariablesVector(numberOfSynchronizingActions);
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
// usedNondetVariablesVector[j] = 0;
// }
//
// // Create DD for first module
// systemDds = createSystemComponentDecisionDiagramm(generationInfo, generationInfo.program.getModule(0), usedNondetVariablesVector);
//
// for (uint_fast64_t i = 1; i < generationInfo.program.getNumberOfModules(); ++i) {
//
// // Create new usedNondetVariablesVector
// std::vector<uint_fast64_t> newUsedNondetVariablesVector(numberOfSynchronizingActions);
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
// // Check if systemDds contains action
// if (std::find(systemDds.allSynchronizingActions.begin(), systemDds.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds.allSynchronizingActions.end()) {
// newUsedNondetVariablesVector[j] = systemDds.synchronizingActionDds[j].usedNondetVariables;
// }
// else{
// newUsedNondetVariablesVector[j] = usedNondetVariablesVector[j];
// }
// }
//
// // Create DD for next module
// systemDds2 = createSystemComponentDecisionDiagramm(generationInfo, generationInfo.program.getModule(i), newUsedNondetVariablesVector);
//
// // SystemDds1 stores the previous modules (already combined)
// systemDds1 = SystemComponentDecisionDiagram<Type>(systemDds);
//
// // SystemDds is used to store combination of SystemDds1 and SystemDds2
// systemDds = SystemComponentDecisionDiagram<Type>(numberOfSynchronizingActions);
//
// // Combine non-synchronizing/independent actions
// systemDds.independentActionDd = combineModules(generationInfo, false, systemDds1.independentActionDd, systemDds2.independentActionDd, systemDds1.identityMatrix, systemDds2.identityMatrix);
//
// // Combine synchronizing actions
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
// // Check if both modules contain the current action
// if (std::find(systemDds1.allSynchronizingActions.begin(), systemDds1.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds1.allSynchronizingActions.end() &&
// std::find(systemDds2.allSynchronizingActions.begin(), systemDds2.allSynchronizingActions.end(), generationInfo.allSynchronizingActions[j]) != systemDds2.allSynchronizingActions.end()) {
// // Both modules contain action
// systemDds.synchronizingActionDds[j] = combineModules(generationInfo, true, systemDds1.synchronizingActionDds[j], systemDds2.synchronizingActionDds[j], systemDds1.identityMatrix, systemDds2.identityMatrix);
// }
// else {
// // Only one or no module contains current action
// systemDds.synchronizingActionDds[j] = combineModules(generationInfo, false, systemDds1.synchronizingActionDds[j], systemDds2.synchronizingActionDds[j], systemDds1.identityMatrix, systemDds2.identityMatrix);
// }
// }
//
// // Combine identity matrix
// systemDds.identityMatrix = systemDds1.identityMatrix * systemDds2.identityMatrix;
//
// // Combine list of synchronizing actions
// systemDds.allSynchronizingActions.insert(systemDds1.allSynchronizingActions.begin(), systemDds1.allSynchronizingActions.end());
// systemDds.allSynchronizingActions.insert(systemDds2.allSynchronizingActions.begin(), systemDds2.allSynchronizingActions.end());
// }
//
// // Combine all DDs
// systemDds = combineSystem(generationInfo, systemDds);
// generationInfo.globalSystemDds = SystemComponentDecisionDiagram<Type>(systemDds);
//
//
// // Build state and transition rewards
// generationInfo.rewardDds = computeRewards(generationInfo, systemDds);
//
// // Create transition to action mapping for MDPs
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// generationInfo.transitionActionDd = computeTransitionAction(generationInfo, systemDds);
// }
//
// // Normalize each row for DTMCs
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
// temporary = storm::dd::Dd<Type>(systemDds.independentActionDd.commandsDd);
// temporary = temporary.sumAbstract(generationInfo.columnMetaVariableNames);
// systemDds.independentActionDd.commandsDd = systemDds.independentActionDd.commandsDd / temporary;
// }
//
// // Get system transition matrix
// storm::dd::Dd<Type> systemTransitionMatrix = systemDds.independentActionDd.commandsDd;
//
// return systemTransitionMatrix;
// }
//
// template <storm::dd::DdType Type>
// SystemComponentDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineSystem(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> systemDds){
//
// uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
// uint_fast64_t max = 0;
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
// storm::dd::Dd<Type> variableDd = generationInfo.manager->getZero();
//
// // Add non-determinism variables for MDPs
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// // Check DD variables
//
// // Look for maximal variable index
// max = systemDds.independentActionDd.usedNondetVariables;
// for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
// if (systemDds.synchronizingActionDds[i].usedNondetVariables > max) {
// max = systemDds.synchronizingActionDds[i].usedNondetVariables;
// }
// }
//
// // Add variables to independent action DD (if required)
// if (max > systemDds.independentActionDd.usedNondetVariables) {
// temporary = generationInfo.manager->getOne();
// for (uint_fast64_t i = systemDds.independentActionDd.usedNondetVariables+1; i <= max; ++i){
//
// // Get variable and set to 0
// variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
// temporary = temporary * variableDd;
//
// }
// systemDds.independentActionDd.commandsDd = systemDds.independentActionDd.commandsDd * temporary;
// systemDds.independentActionDd.usedNondetVariables = max;
// }
//
// // Add variables to synchronized action DDs
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
// if (max > systemDds.synchronizingActionDds[j].usedNondetVariables) {
// temporary = generationInfo.manager->getOne();
// for (uint_fast64_t i = systemDds.synchronizingActionDds[j].usedNondetVariables+1; i <= max; ++i){
//
// // Get variable and set to 0
// variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
// temporary = temporary * variableDd;
//
// }
// systemDds.synchronizingActionDds[j].commandsDd = systemDds.synchronizingActionDds[j].commandsDd * temporary;
// systemDds.synchronizingActionDds[j].usedNondetVariables = max;
// }
// }
//
// // Set variables for synchronization
// temporary = generationInfo.manager->getOne();
// for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
// // Get sync variable
// variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(i), 0);
// temporary = temporary * variableDd;
// }
//
// systemDds.independentActionDd.commandsDd = temporary * systemDds.independentActionDd.commandsDd;
//
// // Set variables for synchronized action DDs
// for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
// temporary = generationInfo.manager->getOne();
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j){
// // Enable synchronizing variable j iff current action i==j
// if (i == j) {
// variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(j), 1);
// temporary = temporary * variableDd;
// }
// else {
// variableDd = generationInfo.manager->getEncoding("sync" + std::to_string(j), 0);
// temporary = temporary * variableDd;
// }
// }
//
// systemDds.synchronizingActionDds[i].commandsDd = temporary * systemDds.synchronizingActionDds[i].commandsDd;
// }
//
// }
//
// // Create transition matrix
// temporary = systemDds.independentActionDd.commandsDd;
// for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
// temporary = temporary + systemDds.synchronizingActionDds[i].commandsDd;
// }
//
// // Store transition matrix in systemDDs structure
// systemDds.independentActionDd.commandsDd = temporary;
//
// return systemDds;
// }
//
// template <storm::dd::DdType Type>
// ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineModules(GenerationInformation const & generationInfo, bool synchronizing, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2, storm::dd::Dd<Type> const& identityDd1, storm::dd::Dd<Type> const& identityDd2){
//
// // Module DD
// ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
//
// if (synchronizing) {
// // Synchronizing actions
//
// // Combine guards (intersection)
// moduleDd.guardDd = moduleDd1.guardDd * moduleDd2.guardDd;
//
// // Combine transitions
// moduleDd.commandsDd = moduleDd1.commandsDd * moduleDd2.commandsDd;
//
// // Update min/max index
// moduleDd.usedNondetVariables = (moduleDd1.usedNondetVariables > moduleDd2.usedNondetVariables) ? moduleDd1.usedNondetVariables : moduleDd2.usedNondetVariables;
//
// } else {
// // Non-synchronizing actions
//
// // Multiply commands with identity matrix (because of non-synchronization)
// moduleDd1.commandsDd = moduleDd1.commandsDd * identityDd2;
// moduleDd2.commandsDd = moduleDd2.commandsDd * identityDd1;
//
// // Combine modules
// switch (generationInfo.program.getModelType()) {
// case storm::prism::Program::ModelType::DTMC:
//
// // No non-determinism, just sum up
// moduleDd.guardDd = moduleDd1.guardDd + moduleDd2.guardDd;
// moduleDd.commandsDd = moduleDd1.commandsDd + moduleDd2.commandsDd;
// moduleDd.usedNondetVariables = 0;
// break;
// case storm::prism::Program::ModelType::MDP:
//
// // Combine modules and solve non-determinism
// moduleDd = combineModulesMDP(generationInfo, moduleDd1, moduleDd2);
// break;
// default:
// STORM_LOG_ASSERT(false, "Illegal model type.");
// }
// }
//
// return moduleDd;
// }
//
// template <storm::dd::DdType Type>
// ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineModulesMDP(GenerationInformation const & generationInfo, ModuleDecisionDiagram<Type> moduleDd1, ModuleDecisionDiagram<Type> moduleDd2){
//
// // Module DD
// ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
//
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
// storm::dd::Dd<Type> variableDd = generationInfo.manager->getZero();
//
// // Check if one command DD equals 0
// if (moduleDd1.commandsDd.isZero()) {
// moduleDd.guardDd = moduleDd2.guardDd;
// moduleDd.commandsDd = moduleDd2.commandsDd;
// moduleDd.usedNondetVariables = moduleDd2.usedNondetVariables;
// return moduleDd;
// }
// if (moduleDd2.commandsDd.isZero()) {
// moduleDd.guardDd = moduleDd1.guardDd;
// moduleDd.commandsDd = moduleDd1.commandsDd;
// moduleDd.usedNondetVariables = moduleDd1.usedNondetVariables;
// return moduleDd;
// }
//
// // Solve non-determinism
//
// // Check index of DD variables
// if (moduleDd1.usedNondetVariables > moduleDd2.usedNondetVariables) {
// temporary = generationInfo.manager->getOne();
//
// for (uint_fast64_t i = moduleDd2.usedNondetVariables+1; i <= moduleDd1.usedNondetVariables; ++i){
// // Get variable and set to 0
// variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
// temporary = temporary * variableDd;
// }
// moduleDd2.commandsDd = moduleDd2.commandsDd * temporary;
// moduleDd2.usedNondetVariables = moduleDd1.usedNondetVariables;
// }
// if (moduleDd2.usedNondetVariables > moduleDd1.usedNondetVariables) {
// temporary = generationInfo.manager->getOne();
//
// for (uint_fast64_t i = moduleDd1.usedNondetVariables+1; i <= moduleDd2.usedNondetVariables; ++i){
// // Get variable and set to 0
// variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
// temporary = temporary * variableDd;
// }
// moduleDd1.commandsDd = moduleDd1.commandsDd * temporary;
// moduleDd1.usedNondetVariables = moduleDd2.usedNondetVariables;
// }
//
// // Get new nondet. variable
// variableDd = variableDd = generationInfo.manager->getEncoding("nondet" + std::to_string(moduleDd1.usedNondetVariables + 1), 1);
//
// // Set nondet. variable
// moduleDd2.commandsDd = moduleDd2.commandsDd * variableDd;
// moduleDd1.commandsDd = moduleDd1.commandsDd * (!variableDd);
//
// // Combine command DDs
// moduleDd.commandsDd = moduleDd1.commandsDd + moduleDd2.commandsDd;
//
// // Combine guard DDs
// moduleDd.guardDd = moduleDd1.guardDd || moduleDd2.guardDd;
//
// moduleDd.usedNondetVariables = moduleDd1.usedNondetVariables + 1;
//
// return moduleDd;
// }
//
// template <storm::dd::DdType Type>
// SystemComponentDecisionDiagram<Type> SymbolicModelAdapter<Type>::createSystemComponentDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, std::vector<uint_fast64_t> usedNondetVariablesVector){
//
// uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
//
// // System Component DD
// SystemComponentDecisionDiagram<Type> systemComponentDd(numberOfSynchronizingActions);
//
// // Create module DD for independent actions
// systemComponentDd.independentActionDd = createModuleDecisionDiagramm(generationInfo, module, "", 0);
//
// // Create module DD for synchronizing actions
// for (uint_fast64_t i = 0; i < numberOfSynchronizingActions; ++i){
//
// if (module.hasAction(generationInfo.allSynchronizingActions[i])){
// systemComponentDd.synchronizingActionDds[i] = createModuleDecisionDiagramm(generationInfo, module, generationInfo.allSynchronizingActions[i], usedNondetVariablesVector[i]);
// }else{
// switch (generationInfo.program.getModelType()){
// case storm::prism::Program::ModelType::DTMC:
// systemComponentDd.synchronizingActionDds[i] = ModuleDecisionDiagram<Type>(generationInfo.manager->getZero(), generationInfo.manager->getZero(), 0);
// break;
// case storm::prism::Program::ModelType::MDP:
// systemComponentDd.synchronizingActionDds[i] = ModuleDecisionDiagram<Type>(generationInfo.manager->getZero(), generationInfo.manager->getZero(), usedNondetVariablesVector[i]);
// break;
// default:
// STORM_LOG_ASSERT(false, "Illegal model type.");
// }
// }
//
// }
//
// // Get module identity matrix
// systemComponentDd.identityMatrix = generationInfo.moduleToIdentityDecisionDiagramMap.at(module.getName());
//
// // Store all synchronizing actions
// systemComponentDd.allSynchronizingActions.insert(module.getActions().begin(), module.getActions().end());
//
// return systemComponentDd;
// }
//
// // TODO
// std::map<std::string, int_fast64_t> getMetaVariableMapping(std::vector<std::string> metaVariables, uint_fast64_t value){
//
// std::map<std::string, int_fast64_t> metaVariableNameToValueMap = std::map<std::string, int_fast64_t>();
//
// for (uint_fast64_t i = 0; i < metaVariables.size(); ++i) {
// if (value & (1ull << (metaVariables.size() - i - 1))) {
// metaVariableNameToValueMap.insert(std::make_pair(metaVariables[i], 1));
// }
// else {
// metaVariableNameToValueMap.insert(std::make_pair(metaVariables[i], 0));
// }
// }
//
// return metaVariableNameToValueMap;
// }
//
// template <storm::dd::DdType Type>
// ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::combineCommandsMDP(std::shared_ptr<storm::dd::DdManager<Type>> const & manager, uint_fast64_t numberOfCommands, std::vector<storm::dd::Dd<Type>> const& commandDds, std::vector<storm::dd::Dd<Type>> const & guardDds, uint_fast64_t usedNondetVariables){
//
// // Module DD
// ModuleDecisionDiagram<Type> moduleDd = ModuleDecisionDiagram<Type>();
//
// // Initialize DDs
// storm::dd::Dd<Type> guardRangeDd = manager->getZero();
// storm::dd::Dd<Type> commandsDd = manager->getZero();
// storm::dd::Dd<Type> temporaryDd = manager->getZero();
//
// // Check for overlapping guards
// storm::dd::Dd<Type> overlappingGuardDd = manager->getZero();
//
// for (uint_fast64_t i = 0; i < numberOfCommands; ++i) {
// overlappingGuardDd = overlappingGuardDd + guardDds[i];
// guardRangeDd = guardRangeDd || guardDds[i];
// }
//
// uint_fast64_t maxChoices = overlappingGuardDd.getMax();
//
// // Check for no choice or no non-determinism
// if (maxChoices == 0 || maxChoices == 1) {
//
// if (maxChoices == 1) {
// // Sum up all command updates
// for (uint_fast64_t i = 0; i < numberOfCommands; ++i) {
// temporaryDd = guardDds[i] * commandDds[i];
// commandsDd = commandsDd + temporaryDd;
// }
// }
//
// moduleDd.guardDd = guardRangeDd;
// moduleDd.commandsDd = commandsDd;
// moduleDd.usedNondetVariables = usedNondetVariables;
//
// return moduleDd;
// }
//
// // Calculate number of required variables (log2(maxChoices))
// uint_fast64_t numberOfBinaryVariables = static_cast<uint_fast64_t>(std::ceil(log2(maxChoices)));
//
// // Allocate local nondet. choice variables
// std::vector<std::string> nondetVariables(numberOfBinaryVariables);
// for (uint_fast64_t i = 1; i <= numberOfBinaryVariables; ++i) {
// nondetVariables[i-1] = "nondet" + std::to_string(usedNondetVariables + i);
// }
//
// // Initialize more DDs
// storm::dd::Dd<Type> equalsNumberOfChoicesDd = manager->getZero();
// std::vector<storm::dd::Dd<Type>> choiceDds(maxChoices);
// std::vector<storm::dd::Dd<Type>> remainingDds(maxChoices);
//
// storm::dd::Dd<Type> temporaryDd1 = manager->getZero();
// storm::dd::Dd<Type> temporaryDd2 = manager->getZero();
//
// for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
//
// // Check for paths with exactly i nondet. choices
// equalsNumberOfChoicesDd = overlappingGuardDd.equals(manager->getConstant(static_cast<double> (currentChoices)));
//
// if (equalsNumberOfChoicesDd.isZero()) continue;
//
// // Reset DDs
// for (uint_fast64_t j = 0; j < currentChoices; ++j) {
// choiceDds[j] = manager->getZero();
// remainingDds[j] = equalsNumberOfChoicesDd;
// }
//
// // Check all commands
// for (uint_fast64_t j = 0; j < numberOfCommands; ++j) {
//
// // Check if command guard overlaps with equalsNumberOfChoicesDd
// temporaryDd1 = guardDds[j] && equalsNumberOfChoicesDd;
// if (temporaryDd1.isZero()) continue;
//
// // Split nondet. choices
// for (uint_fast64_t k = 0; k < currentChoices; ++k) {
//
// // Calculate maximal overlapping parts of command guard and remaining DD (for current index)
// temporaryDd2 = temporaryDd1 && remainingDds[k];
//
// // Check if we can add some overlapping parts to the current index
// if (temporaryDd2 != manager->getZero()) {
//
// // Remove overlapping parts from the remaining DD
// remainingDds[k] = remainingDds[k] && (!temporaryDd2);
//
// // Combine guard (overlapping parts) with command updates
// temporaryDd = temporaryDd2 * commandDds[j];
// // Add command DD to the commands with current index
// choiceDds[k] = choiceDds[k] + temporaryDd;
// }
//
// // Remove overlapping parts from the command guard DD
// temporaryDd1 = temporaryDd1 && (!temporaryDd2);
//
// // Check if the command guard DD is already 0
// if (temporaryDd1.isZero()) break;
// }
// }
//
// // Set nondet. choices for corresponding DDs
// for (uint_fast64_t j = 0; j < currentChoices; ++j) {
//
// temporaryDd1 = manager->getZero();
//
// // Set chosen variables to value j
// temporaryDd1.setValue(getMetaVariableMapping(nondetVariables, j), 1);
//
// // Multiply setting of nondet. variables with corresponding commands
// temporaryDd = temporaryDd1 * choiceDds[j];
// // Sum up all DDs (no non-determinism any more)
// commandsDd = commandsDd + temporaryDd;
// }
//
// // Delete currentChoices out of overlapping DD
// overlappingGuardDd = overlappingGuardDd * (!equalsNumberOfChoicesDd);
// }
//
// moduleDd.guardDd = guardRangeDd;
// moduleDd.commandsDd = commandsDd;
// moduleDd.usedNondetVariables = usedNondetVariables + numberOfBinaryVariables;
//
// return moduleDd;
// }
//
// template <storm::dd::DdType Type>
// ModuleDecisionDiagram<Type> SymbolicModelAdapter<Type>::createModuleDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, std::string const& synchronizingAction, uint_fast64_t usedNondetVariables){
//
// // Module DD
// ModuleDecisionDiagram<Type> moduleDd;
//
// // Set up vectors
// uint_fast64_t numberOfCommands = module.getNumberOfCommands();
// std::vector<storm::dd::Dd<Type>> guardDds(numberOfCommands);
// std::vector<storm::dd::Dd<Type>> commandDds(numberOfCommands);
//
// for (uint_fast64_t j = 0; j < numberOfCommands; ++j) {
//
// storm::prism::Command const& command = module.getCommand(j);
//
// // Check if command action matches requested synchronizing action
// if (synchronizingAction == command.getActionName()) {
//
// // Translate guard
// guardDds[j] = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(command.getGuardExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
//
// if (guardDds[j].isZero()){
// LOG4CPLUS_WARN(logger, "A guard is unsatisfiable.");
// }
//
// // Create command DD
// commandDds[j] = createCommandDecisionDiagramm(generationInfo, module, guardDds[j], command);
//
// commandDds[j] = commandDds[j] * guardDds[j];
//
// // check negative probabilities/rates
// if (commandDds[j].getMin() < 0){
// LOG4CPLUS_WARN(logger, "Negative probabilites/rates in command " << (j + 1) << ".");
// }
// }
// else {
// // Otherwise use zero DDs
// guardDds[j] = generationInfo.manager->getZero();
// commandDds[j] = generationInfo.manager->getZero();
// }
// }
//
// // combine command DDs with guard DDs
// switch (generationInfo.program.getModelType()){
// case storm::prism::Program::ModelType::DTMC:
// moduleDd = combineCommandsDTMC(generationInfo.manager, numberOfCommands, commandDds, guardDds);
// break;
// case storm::prism::Program::ModelType::MDP:
// moduleDd = combineCommandsMDP(generationInfo.manager, numberOfCommands, commandDds, guardDds, usedNondetVariables);
// break;
// default:
// STORM_LOG_ASSERT(false, "Illegal model type.");
// }
//
// return moduleDd;
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createCommandDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Command const& command){
//
// // Command DD
// storm::dd::Dd<Type> commandDd = generationInfo.manager->getZero();
//
// for (uint_fast64_t i = 0; i < command.getNumberOfUpdates(); ++i) {
//
// // Create update DD
// storm::dd::Dd<Type> updateDd = createUpdateDecisionDiagramm(generationInfo, module, guard, command.getUpdate(i));
//
// if (updateDd.isZero()){
// LOG4CPLUS_WARN(logger, "Update " << (i + 1) << " does not do anything.");
// }
//
// // Multiply likelihood expression (MDP: transition probability)
// double p = command.getUpdate(i).getLikelihoodExpression().evaluateAsDouble();
//
// updateDd = updateDd * generationInfo.manager->getConstant(p);
//
// commandDd = commandDd + updateDd;
// }
//
// return commandDd;
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::createUpdateDecisionDiagramm(GenerationInformation const & generationInfo, storm::prism::Module const& module, storm::dd::Dd<Type> const& guard, storm::prism::Update const& update){
//
// // Update DD
// storm::dd::Dd<Type> updateDd = generationInfo.manager->getOne();
//
// // Assignments (integer and boolean)
// std::vector<storm::prism::Assignment> assignments = update.getAssignments();
// for (auto singleAssignment : assignments) {
//
// // Translate first part of assignment
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
//
// temporary = generationInfo.manager->getIdentity(singleAssignment.getVariableName() + "'");
//
// // Translate second part of assignment
// storm::dd::Dd<Type> updateExpr = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(singleAssignment.getExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
//
// storm::dd::Dd<Type> result = updateExpr * guard;
// // Combine first and second part of the assignment
// result = result.equals(temporary);
// result = result * guard;
//
// // Filter range
// result = result * generationInfo.manager->getRange(singleAssignment.getVariableName() + "'");
//
// updateDd = updateDd * result;
// }
//
// // All unused global boolean variables do not change
// for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalBooleanVariables().size(); ++i) {
// storm::prism::BooleanVariable const& booleanVariable = generationInfo.program.getGlobalBooleanVariables().at(i);
// if (update.getAssignmentMapping().find(booleanVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(booleanVariable.getName());
// }
// }
//
// // All unused global integer variables do not change
// for (uint_fast64_t i = 0; i < generationInfo.program.getGlobalIntegerVariables().size(); ++i) {
// storm::prism::IntegerVariable const& integerVariable = generationInfo.program.getGlobalIntegerVariables().at(i);
// if (update.getAssignmentMapping().find(integerVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(integerVariable.getName());
// }
// }
//
// // All unused boolean variables do not change
// for (uint_fast64_t i = 0; i < module.getNumberOfBooleanVariables(); ++i) {
// storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(i);
// if (update.getAssignmentMapping().find(booleanVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(booleanVariable.getName());
// }
// }
//
// // All unused integer variables do not change
// for (uint_fast64_t i = 0; i < module.getNumberOfIntegerVariables(); ++i) {
// storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(i);
// if (update.getAssignmentMapping().find(integerVariable.getName()) == update.getAssignmentMapping().end()) {
// // Multiply identity matrix
// updateDd = updateDd * generationInfo.variableToIdentityDecisionDiagramMap.at(integerVariable.getName());
// }
// }
//
// return updateDd;
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::getInitialStateDecisionDiagram(GenerationInformation const & generationInfo) {
// storm::dd::Dd<Type> initialStates = generationInfo.manager->getOne();
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
//
// // Global Boolean variables
// for (uint_fast64_t j = 0; j < generationInfo.program.getGlobalBooleanVariables().size(); ++j) {
// storm::prism::BooleanVariable const& booleanVariable = generationInfo.program.getGlobalBooleanVariables().at(j);
// temporary = generationInfo.manager->getEncoding(booleanVariable.getName(), booleanVariable.getInitialValueExpression().evaluateAsBool());
// initialStates = initialStates * temporary;
// }
//
// // Global Integer variables
// for (uint_fast64_t j = 0; j < generationInfo.program.getGlobalIntegerVariables().size(); ++j) {
// storm::prism::IntegerVariable const& integerVariable = generationInfo.program.getGlobalIntegerVariables().at(j);
// temporary = generationInfo.manager->getEncoding(integerVariable.getName(), integerVariable.getInitialValueExpression().evaluateAsInt());
// initialStates = initialStates * temporary;
// }
//
// for (uint_fast64_t i = 0; i < generationInfo.program.getNumberOfModules(); ++i) {
// storm::prism::Module const& module = generationInfo.program.getModule(i);
//
// // Boolean variables
// for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) {
// storm::prism::BooleanVariable const& booleanVariable = module.getBooleanVariables().at(j);
// temporary = generationInfo.manager->getEncoding(booleanVariable.getName(), booleanVariable.getInitialValueExpression().evaluateAsBool());
// initialStates = initialStates * temporary;
// }
//
// // Integer variables
// for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) {
// storm::prism::IntegerVariable const& integerVariable = module.getIntegerVariables().at(j);
// temporary = generationInfo.manager->getEncoding(integerVariable.getName(), integerVariable.getInitialValueExpression().evaluateAsInt());
// initialStates = initialStates * temporary;
// }
// }
//
// return initialStates;
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::performReachability(GenerationInformation & generationInfo, storm::dd::Dd<Type> const& systemDd, storm::dd::Dd<Type> const& initialStateDd) {
//
// // Initialize the clock.
// auto clock = std::chrono::high_resolution_clock::now();
//
//
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
// storm::dd::Dd<Type> S;
// storm::dd::Dd<Type> U;
//
// // Get initial state
// storm::dd::Dd<Type> reachableStates = initialStateDd;
//
// // Copy current state
// storm::dd::Dd<Type> newReachableStates = reachableStates;
//
// std::set<std::string> abstractVariables = std::set<std::string>();
//
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// // Synchronizing variables
// if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
// abstractVariables.insert("sync" + std::to_string(i));
// }
// }
// for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
// // Nondet. variables
// if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
// abstractVariables.insert("nondet" + std::to_string(i));
// }
// }
// }
//
// // Create system BDD
// storm::dd::Dd<Type> systemBdd = systemDd.notZero();
//
// // For MDPs, we need to abstract from the nondeterminism variables, but we can do so prior to the
// // reachability analysis.
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// // Abstract from synchronizing and nondet. variables (MDPs)
// systemBdd = systemBdd.existsAbstract(abstractVariables);
// }
//
// // Initialize variables and choose option
// bool changed;
// int iter = 0;
// int option = storm::settings::adapterSettings().getReachabilityMethod();
//
// //TODO: Name reachability options.
// std::cout << "Reachability option: " << option << std::endl;
//
// if (option == 3 || option == 4){
//
// S = storm::dd::Dd<Type>(initialStateDd);
// U = storm::dd::Dd<Type>(initialStateDd);
//
// generationInfo.globalSystemDds.independentActionDd.commandsDd = generationInfo.globalSystemDds.independentActionDd.commandsDd.notZero();
// generationInfo.globalSystemDds.independentActionDd.commandsDd = generationInfo.globalSystemDds.independentActionDd.commandsDd.existsAbstract(abstractVariables);
//
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd = generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd.notZero();
// generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd = generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd.existsAbstract(abstractVariables);
// }
// }
//
// // Perform updates until nothing changes
// do {
// if (option == 1){
// iter++;
// changed = true;
//
// newReachableStates = newReachableStates * systemBdd;
//
// // Abstract from row meta variables
// newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
//
// // Swap column variables to row variables
// newReachableStates.swapVariables(generationInfo.metaVariablePairs);
//
// newReachableStates = newReachableStates * (!reachableStates);
//
// // Check if something has changed
// if (newReachableStates.isZero()) {
// changed = false;
// }
//
// // Update reachableStates DD
// reachableStates = reachableStates + newReachableStates;
//
// } else if (option == 2) {
// iter++;
// changed = false;
//
// newReachableStates = newReachableStates * systemBdd;
//
// // Abstract from row meta variables
// newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
//
// // Swap column variables to row variables
// newReachableStates.swapVariables(generationInfo.metaVariablePairs);
//
// newReachableStates = newReachableStates || reachableStates;
//
// // Check if something has changed
// if (newReachableStates != reachableStates) {
// changed = true;
// }
//
// // Update reachableStates DD
// reachableStates = newReachableStates;
//
// } else if (option == 3) {
// iter++;
// changed = true;
//
// newReachableStates = generationInfo.manager->getZero();
//
// temporary = U * generationInfo.globalSystemDds.independentActionDd.commandsDd;
// newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
// newReachableStates.swapVariables(generationInfo.metaVariablePairs);
// newReachableStates = temporary;
//
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// temporary = U * generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd;
// temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
// temporary.swapVariables(generationInfo.metaVariablePairs);
// newReachableStates = newReachableStates || temporary;
// }
//
// newReachableStates = newReachableStates.existsAbstract(generationInfo.rowMetaVariableNames);
// newReachableStates.swapVariables(generationInfo.metaVariablePairs);
// U = U || newReachableStates;
//
// if (U == S){
// changed = false;
// reachableStates = S;
// break;
// }
//
// S = S || U;
//
// }
// else if (option == 4) {
// iter++;
// changed = true;
//
// temporary = U * generationInfo.globalSystemDds.independentActionDd.commandsDd;
// temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
// temporary.swapVariables(generationInfo.metaVariablePairs);
// U = U || temporary;
//
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// temporary = U * generationInfo.globalSystemDds.synchronizingActionDds[i].commandsDd;
// temporary = temporary.existsAbstract(generationInfo.rowMetaVariableNames);
// temporary.swapVariables(generationInfo.metaVariablePairs);
// U = U || temporary;
// }
//
// U = U * (!S);
//
// S = S + U;
//
// if (U.isZero()){
// changed = false;
// reachableStates = S;
// }
//
// }
// } while (changed);
//
// std::cout << "Performed reachability (" << iter << " iterations) in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
//
// return reachableStates;
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::findDeadlocks(GenerationInformation const & generationInfo, storm::dd::Dd<Type> systemDd, storm::dd::Dd<Type> const& reachableStatesDd) {
//
// // Initialize the clock.
// auto clock = std::chrono::high_resolution_clock::now();
//
// storm::dd::Dd<Type> systemBdd = systemDd.notZero();
//
// std::set<std::string> abstractVariables = std::set<std::string>();
//
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// // Synchronizing variables
// if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
// abstractVariables.insert("sync" + std::to_string(i));
// }
// }
// for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
// // Nondet. variables
// if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
// abstractVariables.insert("nondet" + std::to_string(i));
// }
// }
// }
//
// // Find states with at least one transition
// systemBdd = systemBdd.existsAbstract(generationInfo.columnMetaVariableNames);
//
// // For MDPs, we need to abstract from the nondeterminism variables
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// // Abstract from synchronizing and nondet. variables (MDPs)
// systemBdd = systemBdd.existsAbstract(abstractVariables);
// }
//
// systemBdd = reachableStatesDd * (!systemBdd);
//
// std::cout << "Deadlocks: " << systemBdd.getNonZeroCount() << " fixed." << std::endl;
//
// // Check if there are deadlocks
// if (!systemBdd.isZero()){
//
// storm::dd::Dd<Type> temporary = generationInfo.manager->getOne();
//
// // Get all variable identities
// for (auto variable : generationInfo.rowMetaVariableNames) {
// temporary = temporary * generationInfo.variableToIdentityDecisionDiagramMap.at(variable);
// }
//
// // Add synchronizing and nondet. variables to identity for MDPs (all set to 0)
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i) {
// // Synchronizing variables
// if (systemDd.containsMetaVariable("sync" + std::to_string(i))) {
// temporary = temporary * generationInfo.manager->getEncoding("sync" + std::to_string(i),0);
// }
// }
// for (uint_fast64_t i = 1; i <= generationInfo.numberOfNondetVariables; ++i) {
// // Nondet. variables
// if (systemDd.containsMetaVariable("nondet" + std::to_string(i))) {
// temporary = temporary * generationInfo.manager->getEncoding("nondet" + std::to_string(i), 0);
// }
// }
// }
//
// temporary = temporary * systemBdd;
//
// // Add self-loops to transition matrix
// systemDd = systemDd + temporary;
// }
//
// std::cout << "Fixed deadlocks in " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - clock).count() << "ms." << std::endl;
//
// return systemDd;
// }
//
// template <storm::dd::DdType Type>
// std::pair<std::vector<storm::dd::Dd<Type>>, std::vector<storm::dd::Dd<Type>>> SymbolicModelAdapter<Type>::computeRewards(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> const& systemDds) {
//
// // Get number of reward modules and synchronizing actions
// uint_fast64_t numberOfRewardModules = generationInfo.program.getRewardModels().size();
// uint_fast64_t numberOfSynchronizingActions = generationInfo.allSynchronizingActions.size();
//
// // State reward DD
// std::vector<storm::dd::Dd<Type>> stateRewardsDds = std::vector<storm::dd::Dd<Type>>(numberOfRewardModules);
// // Transition reward DD
// std::vector<storm::dd::Dd<Type>> transitionRewardsDds = std::vector<storm::dd::Dd<Type>>(numberOfRewardModules);
//
// // Initialize DDs
// for (uint_fast64_t i = 0; i < numberOfRewardModules; ++i) {
// stateRewardsDds[i] = generationInfo.manager->getConstant(0);
// transitionRewardsDds[i] = generationInfo.manager->getConstant(0);
// }
//
// storm::dd::Dd<Type> statesDd = generationInfo.manager->getZero();
// storm::dd::Dd<Type> rewardsDd = generationInfo.manager->getZero();
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
//
// // Loop through all reward models
// for (uint_fast64_t i = 0; i < numberOfRewardModules; ++i) {
// storm::prism::RewardModel const& currentRewardModule = generationInfo.program.getRewardModels().at(i);
//
// // State rewards
// for (auto stateReward : currentRewardModule.getStateRewards()) {
//
// // Translate state and reward expression
// statesDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(stateReward.getStatePredicateExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
// rewardsDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(stateReward.getRewardValueExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
//
// // Restrict rewards to states
// temporary = statesDd * rewardsDd;
//
// // Check for negative rewards
// if (temporary.getMin() < 0){
// LOG4CPLUS_WARN(logger, "Negative state reward in reward model " << (i + 1) << ".");
// }
//
// if(temporary.isZero()) {
// LOG4CPLUS_WARN(logger, "Only zero rewards in reward model " << (i + 1) << ".");
// }
//
// // Combine all rewards
// stateRewardsDds[i] = stateRewardsDds[i] + temporary;
// }
//
// // Transition rewards
// for (auto transitionReward : currentRewardModule.getTransitionRewards()) {
//
// // Translate state and reward expression
// statesDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(transitionReward.getStatePredicateExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
// rewardsDd = storm::adapters::SymbolicExpressionAdapter<Type>::translateExpression(transitionReward.getRewardValueExpression().getBaseExpressionPointer(), generationInfo.program, generationInfo.manager);
//
// // Get action name of the transition
// std::string const& rewardAction = transitionReward.getActionName();
//
// if (rewardAction == "") {
// // Take independent action module
// temporary = systemDds.independentActionDd.commandsDd;
// }else {
// // Get module corresponding to the reward action
// for (uint_fast64_t j = 0; j < numberOfSynchronizingActions; ++j) {
// if (generationInfo.allSynchronizingActions[j] == rewardAction) {
// temporary = systemDds.synchronizingActionDds[j].commandsDd;
// break;
// }
// }
// }
//
// // Convert to BDD for MDPs (DTMC need exact values for scaling)
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
// temporary = temporary.notZero();
// }
//
// // Restrict to states and multiply reward values
// temporary = temporary * statesDd;
// temporary = temporary * rewardsDd;
//
// // Check for negative rewards
// if (temporary.getMin() < 0){
// LOG4CPLUS_WARN(logger, "Negative transition reward in reward model " << (i + 1) << ".");
// }
//
// // Combine all rewards
// transitionRewardsDds[i] = transitionRewardsDds[i] + temporary;
// }
// }
//
// // Scale transition rewards for DTMCs
// if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
// for (uint_fast64_t i = 0; i < generationInfo.program.getRewardModels().size(); ++i){
// // Divide transition rewards through transition matrix
// transitionRewardsDds[i] = transitionRewardsDds[i] / systemDds.independentActionDd.commandsDd;
// }
// }
//
// // Pair to store state and transition rewards
// return std::make_pair(stateRewardsDds, transitionRewardsDds);
// }
//
// template <storm::dd::DdType Type>
// storm::dd::Dd<Type> SymbolicModelAdapter<Type>::computeTransitionAction(GenerationInformation const & generationInfo, SystemComponentDecisionDiagram<Type> const& systemDds){
//
// // Transition actions DD
// storm::dd::Dd<Type> transitionActionDd = generationInfo.manager->getZero();
// storm::dd::Dd<Type> temporary = generationInfo.manager->getZero();
//
// // Store action labels for each transition (0 iff no action/tau/epsilon)
// storm::dd::Dd<Type> commandsBdd = generationInfo.manager->getZero();
// for (uint_fast64_t i = 0; i < generationInfo.allSynchronizingActions.size(); ++i){
// // Get action transition matrix as BDD
// commandsBdd = systemDds.synchronizingActionDds[i].commandsDd.notZero();
// commandsBdd = commandsBdd.existsAbstract(generationInfo.columnMetaVariableNames);
//
// // Add action index
// temporary = commandsBdd * generationInfo.manager->getConstant(i + 1);
// transitionActionDd = transitionActionDd + temporary;
// }
//
// return transitionActionDd;
// }
// Explicitly instantiate the symbolic expression adapter
template class DdPrismModelBuilder<storm::dd::DdType::CUDD>;
} // namespace adapters
} // namespace storm