2#include <boost/graph/adjacency_list.hpp>
3#include <boost/graph/strong_components.hpp>
10namespace elimination_actions {
14 variables.push_back(variable);
17 allVariablesUnfoldable =
false;
23 for (
auto var : variables) {
26 res += var.janiVariableName;
43 bool allUnfolded =
true;
56 if (variable.expressionVariableName == expressionVariableName)
59 STORM_LOG_THROW(
false, storm::exceptions::InvalidOperationException,
"The UnfoldDependencyGraph does not contain the variable " + expressionVariableName);
65 std::vector<uint32_t> res;
66 std::set<uint32_t> closedSet;
68 while (closedSet.count(groupIndex) == 0) {
69 uint32_t current = groupIndex;
77 if (closedSet.count(dep) == 0 && current != dep) {
84 closedSet.insert(current);
85 if (includeSelf || current != groupIndex)
86 res.push_back(current);
94 for (uint32_t group : groups) {
101 std::set<uint32_t> res;
109void UnfoldDependencyGraph::buildGroups(
Model &model) {
110 std::vector<std::pair<std::string, VariableSet *>> variableSets;
113 for (
auto &automaton : model.getAutomata()) variableSets.emplace_back(automaton.getName(), &automaton.getVariables());
115 std::vector<VariableInfo> variables;
117 for (
const auto &variableSet : variableSets) {
118 for (
auto &var : *variableSet.second) {
119 bool isConstBounded =
false;
120 if (var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType()) {
121 auto biVar = var.getType().asBoundedType();
122 if (biVar.hasLowerBound() && biVar.hasUpperBound() && !biVar.getLowerBound().containsVariables() &&
123 !biVar.getUpperBound().containsVariables()) {
124 int lowerBound = biVar.getLowerBound().evaluateAsInt();
125 int upperBound = biVar.getUpperBound().evaluateAsInt();
127 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
true,
128 upperBound - lowerBound + 1);
130 isConstBounded =
true;
132 }
else if (var.getType().isBasicType() && var.getType().asBasicType().isBooleanType()) {
133 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
true, 2);
135 isConstBounded =
true;
137 if (!isConstBounded) {
140 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
false, 0);
145 boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> graph(variables.size());
147 for (
auto &automaton : model.getAutomata()) {
148 for (
auto &janiEdge : automaton.getEdges()) {
149 for (
auto &dest : janiEdge.getDestinations()) {
150 for (
auto &asg : dest.getOrderedAssignments().getAllAssignments()) {
151 std::string leftName = asg.getExpressionVariable().getName();
152 uint64_t lIndex = std::distance(variables.begin(), std::find_if(variables.begin(), variables.end(), [leftName](VariableInfo &v) {
153 return v.expressionVariableName == leftName;
156 for (
auto &rightVar : asg.getAssignedExpression().
getVariables()) {
157 const std::string &rightName = rightVar.getName();
158 uint64_t rIndex = std::distance(variables.begin(), std::find_if(variables.begin(), variables.end(), [rightName](VariableInfo &v) {
159 return v.expressionVariableName == rightName;
161 if (rIndex == lIndex)
165 if (!edge(lIndex, rIndex, graph).second) {
166 add_edge(lIndex, rIndex, graph);
175 std::vector<int> sccs(variables.size());
177 int num = strong_components(graph, boost::make_iterator_property_map(sccs.begin(), get(boost::vertex_index, graph), sccs[0]));
179 for (
int i = 0;
i < num;
i++) {
183 std::vector<int>::iterator
i;
184 for (i = sccs.begin();
i != sccs.end(); ++
i) {
185 int index =
i - sccs.begin();
190 for (uint64_t i = 0;
i < graph.m_vertices.size();
i++) {
191 for (
const auto &outEdge : graph.m_vertices[
i].m_out_edges) {
192 unsigned long target =
findGroupIndex(variables[outEdge.m_target].expressionVariableName);
207 bool isConstBoundedInteger,
int domainSize)
208 : expressionVariableName(expressionVariableName),
209 janiVariableName(janiVariableName),
211 automatonName(automatonName),
212 isConstBoundedInteger(isConstBoundedInteger),
213 domainSize(domainSize) {}
216 int groupCounter = 0;
218 std::cout <<
"\nVariable Group " << groupCounter <<
'\n';
219 if (group.allVariablesUnfoldable) {
220 std::cout <<
"\tDomain size: " << group.domainSize <<
'\n';
221 std::cout <<
"\tCan be unfolded\n";
223 std::cout <<
"\tCan not be unfolded\n";
225 std::cout <<
"\tVariables:\n";
226 for (
const auto &var : group.variables) {
227 std::cout <<
"\t\t" << var.expressionVariableName;
228 if (var.isConstBoundedInteger)
229 std::cout <<
" (const-bounded integer with domain size " << var.domainSize <<
")\n";
231 std::cout <<
" (not a const-bounded integer)\n";
233 if (group.dependencies.empty())
234 std::cout <<
"\tNo Dependencies\n";
236 std::cout <<
"\tDependencies:\n";
237 for (
auto dep : group.dependencies) {
238 std::cout <<
"\t\t" << dep <<
'\n';
247 return std::all_of(dependencies.begin(), dependencies.end(), [
this](uint32_t dep) { return this->variableGroups[dep].allVariablesUnfoldable; });
257 res +=
"{" + group.getVariablesAsString() +
"}:";
258 if (!group.dependencies.empty()) {
259 res +=
"\n\tDepends on ";
260 for (uint32_t dep : group.dependencies) res +=
"{" +
variableGroups[dep].getVariablesAsString() +
"}, ";
261 if (allDependencies.size() > group.dependencies.size()) {
263 for (uint32_t dep : allDependencies) {
264 if (group.dependencies.count(dep) == 0)
267 res = res.substr(0, res.length() - 2);
270 res = res.substr(0, res.length() - 2);
277 res +=
"Can be unfolded\n";
279 res +=
"Can't be unfolded:\n";
280 for (
const auto &var : group.variables) {
281 if (!var.isConstBoundedInteger)
282 res +=
"\t\tVariable " + var.expressionVariableName +
" is not a const-bounded integer\n";
284 for (
auto dep : allDependencies) {
286 res +=
"\t\tDependency {" +
variableGroups[dep].getVariablesAsString() +
"} can't be unfolded\n";
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
void addVariable(VariableInfo variable)
std::string getVariablesAsString()
VariableInfo(std::string expressionVariableName, std::string janiVariableName, bool isGlobal, std::string automatonName, bool isConstBoundedInteger, int domainSize)
bool isConstBoundedInteger
std::vector< VariableGroup > variableGroups
void markUnfolded(uint32_t groupIndex)
uint32_t getTotalBlowup(std::vector< uint32_t > groups)
std::set< uint32_t > getGroupsWithNoDependencies()
std::vector< uint32_t > getOrderedDependencies(uint32_t groupIndex, bool includeSelf=false)
UnfoldDependencyGraph(Model &model)
bool areDependenciesUnfoldable(uint32_t groupIndex)
uint32_t findGroupIndex(std::string variableName)
#define STORM_LOG_THROW(cond, exception, message)
std::set< storm::RationalFunctionVariable > getVariables(std::vector< storm::RationalFunction > const &vector)