2#include <boost/graph/adjacency_list.hpp>
3#include <boost/graph/strong_components.hpp>
27 res += var.janiVariableName;
45 bool allUnfolded =
true;
59 if (variable.expressionVariableName == expressionVariableName) {
66 "The UnfoldDependencyGraph does not contain the variable " + expressionVariableName +
".");
72 std::vector<uint32_t> res;
73 std::set<uint32_t> closedSet;
75 while (closedSet.count(groupIndex) == 0) {
76 uint32_t current = groupIndex;
85 if (closedSet.count(dep) == 0 && current != dep) {
92 closedSet.insert(current);
93 if (includeSelf || current != groupIndex) {
94 res.push_back(current);
103 for (uint32_t group : groups) {
110 std::set<uint32_t> res;
120void UnfoldDependencyGraph::buildGroups(
Model &model) {
121 std::vector<std::pair<std::string, VariableSet *>> variableSets;
125 variableSets.emplace_back(automaton.getName(), &automaton.getVariables());
128 std::vector<VariableInfo> variables;
130 for (
const auto &variableSet : variableSets) {
131 for (
auto &var : *variableSet.second) {
132 bool isConstBounded =
false;
133 if (var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType()) {
134 auto biVar = var.getType().asBoundedType();
135 if (biVar.hasLowerBound() && biVar.hasUpperBound() && !biVar.getLowerBound().containsVariables() &&
136 !biVar.getUpperBound().containsVariables()) {
137 int lowerBound = biVar.getLowerBound().evaluateAsInt();
138 int upperBound = biVar.getUpperBound().evaluateAsInt();
140 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
true,
141 upperBound - lowerBound + 1);
143 isConstBounded =
true;
145 }
else if (var.getType().isBasicType() && var.getType().asBasicType().isBooleanType()) {
146 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
true, 2);
148 isConstBounded =
true;
150 if (!isConstBounded) {
153 variables.emplace_back(var.getExpressionVariable().getName(), var.getName(), variableSet.first ==
"", variableSet.first,
false, 0);
158 boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> graph(variables.size());
161 for (
auto &janiEdge : automaton.getEdges()) {
162 for (
auto &dest : janiEdge.getDestinations()) {
163 for (
auto &asg : dest.getOrderedAssignments().getAllAssignments()) {
164 std::string leftName = asg.getExpressionVariable().getName();
165 uint64_t lIndex = std::distance(variables.begin(), std::find_if(variables.begin(), variables.end(), [leftName](
VariableInfo &v) {
166 return v.expressionVariableName == leftName;
169 for (
auto &rightVar : asg.getAssignedExpression().getVariables()) {
170 const std::string &rightName = rightVar.getName();
171 uint64_t rIndex = std::distance(variables.begin(), std::find_if(variables.begin(), variables.end(), [rightName](
VariableInfo &v) {
172 return v.expressionVariableName == rightName;
174 if (rIndex == lIndex) {
179 if (!edge(lIndex, rIndex, graph).second) {
180 add_edge(lIndex, rIndex, graph);
189 std::vector<int> sccs(variables.size());
191 int num = strong_components(graph, boost::make_iterator_property_map(sccs.begin(), get(boost::vertex_index, graph), sccs[0]));
193 for (
int i = 0;
i < num;
i++) {
197 std::vector<int>::iterator
i;
198 for (i = sccs.begin(); i != sccs.end(); ++i) {
199 int index =
i - sccs.begin();
204 for (uint64_t i = 0;
i < graph.m_vertices.size();
i++) {
205 for (
const auto &outEdge : graph.m_vertices[i].m_out_edges) {
206 unsigned long target =
findGroupIndex(variables[outEdge.m_target].expressionVariableName);
230 int groupCounter = 0;
232 std::cout <<
"\nVariable Group " << groupCounter <<
'\n';
233 if (group.allVariablesUnfoldable) {
234 std::cout <<
"\tDomain size: " << group.domainSize <<
'\n';
235 std::cout <<
"\tCan be unfolded\n";
237 std::cout <<
"\tCan not be unfolded\n";
239 std::cout <<
"\tVariables:\n";
240 for (
const auto &var : group.variables) {
241 std::cout <<
"\t\t" << var.expressionVariableName;
242 if (var.isConstBoundedInteger) {
243 std::cout <<
" (const-bounded integer with domain size " << var.domainSize <<
")\n";
245 std::cout <<
" (not a const-bounded integer)\n";
248 if (group.dependencies.empty()) {
249 std::cout <<
"\tNo Dependencies\n";
251 std::cout <<
"\tDependencies:\n";
253 for (
auto dep : group.dependencies) {
254 std::cout <<
"\t\t" << dep <<
'\n';
263 return std::all_of(dependencies.begin(), dependencies.end(), [
this](uint32_t dep) { return this->variableGroups[dep].allVariablesUnfoldable; });
273 res +=
"{" + group.getVariablesAsString() +
"}:";
274 if (!group.dependencies.empty()) {
275 res +=
"\n\tDepends on ";
276 for (uint32_t dep : group.dependencies) {
279 if (allDependencies.size() > group.dependencies.size()) {
281 for (uint32_t dep : allDependencies) {
282 if (group.dependencies.count(dep) == 0) {
286 res = res.substr(0, res.length() - 2);
289 res = res.substr(0, res.length() - 2);
293 if (group.unfolded) {
296 res +=
"Can be unfolded\n";
298 res +=
"Can't be unfolded:\n";
299 for (
const auto &var : group.variables) {
300 if (!var.isConstBoundedInteger) {
301 res +=
"\t\tVariable " + var.expressionVariableName +
" is not a const-bounded integer\n";
304 for (
auto dep : allDependencies) {
306 res +=
"\t\tDependency {" +
variableGroups[dep].getVariablesAsString() +
"} can't be unfolded\n";
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
std::vector< Automaton > & getAutomata()
Retrieves the automata of the model.
bool allDependenciesUnfolded
std::vector< VariableInfo > variables
bool allVariablesUnfoldable
void addVariable(VariableInfo variable)
std::string getVariablesAsString()
std::string janiVariableName
std::string automatonName
VariableInfo(std::string expressionVariableName, std::string janiVariableName, bool isGlobal, std::string automatonName, bool isConstBoundedInteger, int domainSize)
bool isConstBoundedInteger
std::string expressionVariableName
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)