|
|
@ -717,7 +717,7 @@ namespace storm { |
|
|
|
} |
|
|
|
|
|
|
|
Program Program::substituteConstants() const { |
|
|
|
// We start by creating the appropriate substitution
|
|
|
|
// We start by creating the appropriate substitution.
|
|
|
|
std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution; |
|
|
|
std::vector<Constant> newConstants(this->getConstants()); |
|
|
|
for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) { |
|
|
@ -734,12 +734,6 @@ namespace storm { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
|
|
|
|
// maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
|
|
|
|
// commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
|
|
|
|
// remove the forced synchronization that was there before.
|
|
|
|
std::set<uint_fast64_t> actionIndicesToDelete; |
|
|
|
|
|
|
|
// Now we can substitute the constants in all expressions appearing in the program.
|
|
|
|
std::vector<BooleanVariable> newBooleanVariables; |
|
|
|
newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables()); |
|
|
@ -763,9 +757,6 @@ namespace storm { |
|
|
|
newModules.reserve(this->getNumberOfModules()); |
|
|
|
for (auto const& module : this->getModules()) { |
|
|
|
newModules.emplace_back(module.substitute(constantSubstitution)); |
|
|
|
|
|
|
|
// Determine the set of action indices that have been deleted entirely.
|
|
|
|
std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(), newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(), std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin())); |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<RewardModel> newRewardModels; |
|
|
@ -782,37 +773,7 @@ namespace storm { |
|
|
|
newLabels.emplace_back(label.substitute(constantSubstitution)); |
|
|
|
} |
|
|
|
|
|
|
|
// If we have to delete whole actions, do so now.
|
|
|
|
std::map<std::string, uint_fast64_t> newActionToIndexMap; |
|
|
|
if (!actionIndicesToDelete.empty()) { |
|
|
|
boost::container::flat_set<uint_fast64_t> actionsToKeep; |
|
|
|
std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(), actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin())); |
|
|
|
|
|
|
|
// Insert the silent action as this is not contained in the synchronizing action indices.
|
|
|
|
actionsToKeep.insert(0); |
|
|
|
|
|
|
|
std::vector<Module> cleanedModules; |
|
|
|
cleanedModules.reserve(this->getNumberOfModules()); |
|
|
|
for (auto const& module : newModules) { |
|
|
|
cleanedModules.emplace_back(module.restrictCommands(actionsToKeep)); |
|
|
|
} |
|
|
|
newModules = std::move(cleanedModules); |
|
|
|
|
|
|
|
std::vector<RewardModel> cleanedRewardModels; |
|
|
|
cleanedRewardModels.reserve(this->getNumberOfRewardModels()); |
|
|
|
for (auto const& rewardModel : newRewardModels) { |
|
|
|
cleanedRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep)); |
|
|
|
} |
|
|
|
newRewardModels = std::move(cleanedRewardModels); |
|
|
|
|
|
|
|
for (auto const& entry : this->getActionNameToIndexMapping()) { |
|
|
|
if (actionsToKeep.find(entry.second) != actionsToKeep.end()) { |
|
|
|
newActionToIndexMap.emplace(entry.first, entry.second); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, actionIndicesToDelete.empty() ? this->getActionNameToIndexMapping() : newActionToIndexMap, newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); |
|
|
|
return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, newModules, this->getActionNameToIndexMapping(), newRewardModels, newLabels, newInitialConstruct, this->getOptionalSystemCompositionConstruct()); |
|
|
|
} |
|
|
|
|
|
|
|
void Program::checkValidity(Program::ValidityCheckLevel lvl) const { |
|
|
@ -1195,13 +1156,22 @@ namespace storm { |
|
|
|
// Start by substituting the constants, because this will potentially erase some commands or even actions.
|
|
|
|
Program substitutedProgram = this->substituteConstants(); |
|
|
|
|
|
|
|
// As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
|
|
|
|
// maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
|
|
|
|
// commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
|
|
|
|
// remove the forced synchronization that was there before.
|
|
|
|
std::set<uint_fast64_t> actionIndicesToDelete; |
|
|
|
|
|
|
|
std::vector<Module> newModules; |
|
|
|
std::vector<Constant> newConstants = substitutedProgram.getConstants(); |
|
|
|
for (auto const& module : substitutedProgram.getModules()) { |
|
|
|
// Remove identity assignments from the updates.
|
|
|
|
|
|
|
|
// Discard all commands with a guard equivalent to false and remove identity assignments from the updates.
|
|
|
|
std::vector<Command> newCommands; |
|
|
|
for (auto const& command : module.getCommands()) { |
|
|
|
newCommands.emplace_back(command.removeIdentityAssignmentsFromUpdates()); |
|
|
|
if (!command.getGuardExpression().isFalse()) { |
|
|
|
newCommands.emplace_back(command.removeIdentityAssignmentsFromUpdates()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Substitute variables by global constants if possible.
|
|
|
@ -1214,38 +1184,44 @@ namespace storm { |
|
|
|
integerVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression()); |
|
|
|
} |
|
|
|
|
|
|
|
// Collect all variables that are being written. These variables cannot be turned to constants.
|
|
|
|
for (auto const& command : newCommands) { |
|
|
|
// Check all updates.
|
|
|
|
for (auto const& update : command.getUpdates()) { |
|
|
|
// Check all assignments.
|
|
|
|
for (auto const& assignment : update.getAssignments()) { |
|
|
|
auto bit = booleanVars.find(assignment.getVariable()); |
|
|
|
if (bit != booleanVars.end()) { |
|
|
|
booleanVars.erase(bit); |
|
|
|
if (assignment.getVariable().getType().isBooleanType()) { |
|
|
|
auto it = booleanVars.find(assignment.getVariable()); |
|
|
|
if (it != booleanVars.end()) { |
|
|
|
booleanVars.erase(it); |
|
|
|
} |
|
|
|
} else { |
|
|
|
auto iit = integerVars.find(assignment.getVariable()); |
|
|
|
if (iit != integerVars.end()) { |
|
|
|
integerVars.erase(iit); |
|
|
|
auto it = integerVars.find(assignment.getVariable()); |
|
|
|
if (it != integerVars.end()) { |
|
|
|
integerVars.erase(it); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<storm::prism::BooleanVariable> newBVars; |
|
|
|
std::vector<storm::prism::BooleanVariable> newBooleanVars; |
|
|
|
for (auto const& variable : module.getBooleanVariables()) { |
|
|
|
if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) { |
|
|
|
newBVars.push_back(variable); |
|
|
|
newBooleanVars.push_back(variable); |
|
|
|
} |
|
|
|
} |
|
|
|
std::vector<storm::prism::IntegerVariable> newIVars; |
|
|
|
std::vector<storm::prism::IntegerVariable> newIntegerVars; |
|
|
|
for (auto const& variable : module.getIntegerVariables()) { |
|
|
|
if (integerVars.find(variable.getExpressionVariable()) == integerVars.end()) { |
|
|
|
newIVars.push_back(variable); |
|
|
|
newIntegerVars.push_back(variable); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
newModules.emplace_back(module.getName(), newBVars, newIVars, newCommands); |
|
|
|
newModules.emplace_back(module.getName(), newBooleanVars, newIntegerVars, newCommands); |
|
|
|
|
|
|
|
// Determine the set of action indices that have been deleted entirely.
|
|
|
|
std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(), newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(), std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin())); |
|
|
|
|
|
|
|
for (auto const& entry : booleanVars) { |
|
|
|
newConstants.emplace_back(entry.first, entry.second); |
|
|
@ -1256,11 +1232,36 @@ namespace storm { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return substitutedProgram.replaceModulesAndConstantsInProgram(newModules, newConstants); |
|
|
|
} |
|
|
|
|
|
|
|
Program Program::replaceModulesAndConstantsInProgram(std::vector<Module> const& newModules, std::vector<Constant> const& newConstants) { |
|
|
|
return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, getActionNameToIndexMapping(), getRewardModels(), getLabels(), getInitialConstruct(), this->getOptionalSystemCompositionConstruct()); |
|
|
|
// If we have to delete whole actions, do so now.
|
|
|
|
std::map<std::string, uint_fast64_t> newActionToIndexMap; |
|
|
|
std::vector<RewardModel> newRewardModels; |
|
|
|
if (!actionIndicesToDelete.empty()) { |
|
|
|
boost::container::flat_set<uint_fast64_t> actionsToKeep; |
|
|
|
std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(), actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin())); |
|
|
|
|
|
|
|
// Insert the silent action as this is not contained in the synchronizing action indices.
|
|
|
|
actionsToKeep.insert(0); |
|
|
|
|
|
|
|
std::vector<Module> cleanedModules; |
|
|
|
cleanedModules.reserve(newModules.size()); |
|
|
|
for (auto const& module : newModules) { |
|
|
|
cleanedModules.emplace_back(module.restrictCommands(actionsToKeep)); |
|
|
|
} |
|
|
|
newModules = std::move(cleanedModules); |
|
|
|
|
|
|
|
newRewardModels.reserve(substitutedProgram.getNumberOfRewardModels()); |
|
|
|
for (auto const& rewardModel : substitutedProgram.getRewardModels()) { |
|
|
|
newRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep)); |
|
|
|
} |
|
|
|
|
|
|
|
for (auto const& entry : this->getActionNameToIndexMapping()) { |
|
|
|
if (actionsToKeep.find(entry.second) != actionsToKeep.end()) { |
|
|
|
newActionToIndexMap.emplace(entry.first, entry.second); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(), newModules, actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap, actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, getLabels(), getInitialConstruct(), this->getOptionalSystemCompositionConstruct()); |
|
|
|
} |
|
|
|
|
|
|
|
Program Program::flattenModules(std::unique_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const { |
|
|
|