Browse Source
storm-conv: Added ability to make global variables of a jani model local (or vice versa)
main
storm-conv: Added ability to make global variables of a jani model local (or vice versa)
main
13 changed files with 343 additions and 7 deletions
-
20src/storm-conv/api/storm-conv.cpp
-
4src/storm-conv/converter/options/JaniConversionOptions.cpp
-
6src/storm-conv/converter/options/JaniConversionOptions.h
-
6src/storm-conv/settings/modules/JaniExportSettings.cpp
-
3src/storm-conv/settings/modules/JaniExportSettings.h
-
2src/storm/storage/jani/JaniLocationExpander.cpp
-
164src/storm/storage/jani/JaniScopeChanger.cpp
-
57src/storm/storage/jani/JaniScopeChanger.h
-
15src/storm/storage/jani/LValue.cpp
-
20src/storm/storage/jani/Property.cpp
-
3src/storm/storage/jani/Property.h
-
45src/storm/storage/jani/VariableSet.cpp
-
5src/storm/storage/jani/VariableSet.h
@ -0,0 +1,164 @@ |
|||||
|
#include "storm/storage/jani/JaniScopeChanger.h"
|
||||
|
|
||||
|
#include <map>
|
||||
|
#include <set>
|
||||
|
#include <boost/any.hpp>
|
||||
|
|
||||
|
#include "storm/storage/expressions/Variable.h"
|
||||
|
#include "storm/storage/jani/Model.h"
|
||||
|
#include "storm/storage/jani/Property.h"
|
||||
|
#include "storm/storage/jani/traverser/JaniTraverser.h"
|
||||
|
|
||||
|
namespace storm { |
||||
|
namespace jani { |
||||
|
|
||||
|
namespace detail { |
||||
|
class VariableAccessedTraverser : public ConstJaniTraverser { |
||||
|
public: |
||||
|
VariableAccessedTraverser(std::set<storm::expressions::Variable> const& varSet) : varSet(varSet) { |
||||
|
// Intentionally left empty
|
||||
|
} |
||||
|
using ConstJaniTraverser::traverse; |
||||
|
|
||||
|
virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { |
||||
|
bool* result = boost::any_cast<bool *>(data); |
||||
|
if (*result) { return; } |
||||
|
*result = expression.containsVariable(varSet); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
std::set<storm::expressions::Variable> const& varSet; |
||||
|
}; |
||||
|
|
||||
|
std::set<uint64_t> getAutomataAccessingVariable(storm::expressions::Variable const& variable, Model const& model) { |
||||
|
std::set<uint64_t> res; |
||||
|
for (uint64_t i = 0; i < model.getNumberOfAutomata(); ++i) { |
||||
|
if (model.getAutomaton(i).getVariables().hasVariable(variable)) { |
||||
|
res.insert(i); |
||||
|
} else { |
||||
|
VariableAccessedTraverser vat({variable}); |
||||
|
bool varAccessed = false; |
||||
|
vat.traverse(model.getAutomaton(i), &varAccessed); |
||||
|
if (varAccessed) { |
||||
|
res.insert(i); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return res; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void JaniScopeChanger::makeVariableGlobal(storm::expressions::Variable const& variable, Model& model) const { |
||||
|
uint64_t automatonIndex = 0; |
||||
|
for (; automatonIndex < model.getNumberOfAutomata(); ++automatonIndex) { |
||||
|
if (model.getAutomaton(automatonIndex).getVariables().hasVariable(variable)) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
std::map<Variable const*, std::reference_wrapper<Variable const>> remapping; |
||||
|
auto oldJaniVar = model.getAutomaton(automatonIndex).getVariables().eraseVariable(variable); |
||||
|
remapping.emplace(oldJaniVar.get(), model.addVariable(*oldJaniVar)); |
||||
|
|
||||
|
// Only one automaton accesses this variable
|
||||
|
model.getAutomaton(automatonIndex).changeAssignmentVariables(remapping); |
||||
|
} |
||||
|
|
||||
|
void JaniScopeChanger::makeVariableLocal(storm::expressions::Variable const& variable, Model& model, uint64_t automatonIndex) const { |
||||
|
std::map<Variable const*, std::reference_wrapper<Variable const>> remapping; |
||||
|
auto oldJaniVar = model.getGlobalVariables().eraseVariable(variable); |
||||
|
remapping.emplace(oldJaniVar.get(), model.getAutomaton(automatonIndex).addVariable(*oldJaniVar)); |
||||
|
// Only one automaton accesses this variable (otherwise this call would be illegal)
|
||||
|
model.getAutomaton(automatonIndex).changeAssignmentVariables(remapping); |
||||
|
} |
||||
|
|
||||
|
bool JaniScopeChanger::canMakeVariableGlobal(storm::expressions::Variable const& variable, Model const& model) const { |
||||
|
if (model.hasGlobalVariable(variable.getName())) { |
||||
|
return false; |
||||
|
} |
||||
|
// Check whether there are multiple local variables with this name
|
||||
|
bool foundVar = false; |
||||
|
for (auto const& aut : model.getAutomata()) { |
||||
|
if (aut.hasVariable(variable.getName())) { |
||||
|
if (foundVar) { |
||||
|
return false; |
||||
|
} |
||||
|
foundVar = true; |
||||
|
} |
||||
|
} |
||||
|
return foundVar; |
||||
|
} |
||||
|
|
||||
|
std::pair<bool, uint64_t> JaniScopeChanger::canMakeVariableLocal(storm::expressions::Variable const& variable, Model const& model, std::vector<Property> const& properties, boost::optional<uint64_t> automatonIndex) const { |
||||
|
uint64_t index = model.getNumberOfAutomata(); |
||||
|
|
||||
|
if (!model.getGlobalVariables().hasVariable(variable)) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
|
||||
|
auto accessingAutomata = detail::getAutomataAccessingVariable(variable, model); |
||||
|
if (accessingAutomata.size() > 1 || (automatonIndex.is_initialized() && accessingAutomata.count(automatonIndex.get()) == 0)) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
if (model.getInitialStatesRestriction().containsVariable({variable})) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
for (auto const& rewExp : model.getNonTrivialRewardExpressions()) { |
||||
|
if (rewExp.second.containsVariable({variable})) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
} |
||||
|
for (auto const& funDef : model.getGlobalFunctionDefinitions()) { |
||||
|
if (funDef.second.getFunctionBody().containsVariable({variable})) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
} |
||||
|
for (auto const& p : properties) { |
||||
|
if (p.getUsedVariablesAndConstants().count(variable) > 0) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
if (p.getUsedLabels().count(variable.getName()) > 0) { |
||||
|
return {false, index}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (accessingAutomata.empty()) { |
||||
|
index = automatonIndex.is_initialized() ? automatonIndex.get() : 0; |
||||
|
} else { |
||||
|
index = *accessingAutomata.begin(); |
||||
|
assert(!automatonIndex.is_initialized() || index == automatonIndex.get()); |
||||
|
} |
||||
|
return {true, index}; |
||||
|
} |
||||
|
|
||||
|
void JaniScopeChanger::makeVariablesGlobal(Model& model) const { |
||||
|
for (uint64_t i = 0; i < model.getNumberOfAutomata(); ++i) { |
||||
|
// Make sure to not erase from a set while iterating over it...
|
||||
|
std::set<storm::expressions::Variable> varsToMakeGlobal; |
||||
|
for (auto const& v : model.getAutomaton(i).getVariables()) { |
||||
|
if (canMakeVariableGlobal(v.getExpressionVariable(), model)) { |
||||
|
varsToMakeGlobal.insert(v.getExpressionVariable()); |
||||
|
} |
||||
|
} |
||||
|
for (auto const& v : varsToMakeGlobal) { |
||||
|
makeVariableGlobal(v, model); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void JaniScopeChanger::makeVariablesLocal(Model& model, std::vector<Property> const& properties) const { |
||||
|
// Make sure to not erase from a set while iterating over it...
|
||||
|
std::map<storm::expressions::Variable, uint64_t> varsToMakeLocal; |
||||
|
for (auto const& v : model.getGlobalVariables()) { |
||||
|
auto makeLocal = canMakeVariableLocal(v.getExpressionVariable(), model, properties); |
||||
|
if (makeLocal.first) { |
||||
|
varsToMakeLocal[v.getExpressionVariable()] = makeLocal.second; |
||||
|
} |
||||
|
} |
||||
|
for (auto const& v : varsToMakeLocal) { |
||||
|
makeVariableLocal(v.first, model, v.second); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <vector> |
||||
|
#include <boost/optional.hpp> |
||||
|
|
||||
|
namespace storm { |
||||
|
|
||||
|
namespace expressions { |
||||
|
class Variable; |
||||
|
} |
||||
|
|
||||
|
namespace jani { |
||||
|
|
||||
|
class Model; |
||||
|
class Property; |
||||
|
|
||||
|
class JaniScopeChanger { |
||||
|
public: |
||||
|
JaniScopeChanger() = default; |
||||
|
|
||||
|
/*! |
||||
|
* Moves the given variable to the global scope. |
||||
|
* It is *not* checked whether this introduces name clashes |
||||
|
*/ |
||||
|
void makeVariableGlobal(storm::expressions::Variable const& variable, Model& model) const; |
||||
|
|
||||
|
/*! |
||||
|
* Moves the given variable into the local scope of the automaton with the given index. |
||||
|
* It is *not* checked whether this introduces out-of-scope accesses. |
||||
|
*/ |
||||
|
void makeVariableLocal(storm::expressions::Variable const& variable, Model& model, uint64_t automatonIndex) const; |
||||
|
|
||||
|
/*! |
||||
|
* Checks whether this variable can be made global without introducing name clashes. |
||||
|
*/ |
||||
|
bool canMakeVariableGlobal(storm::expressions::Variable const& variable, Model const& model) const; |
||||
|
|
||||
|
/*! |
||||
|
* Checks whether this variable can be made local without introducing out-of-scope accesses. |
||||
|
* Returns true if this is a case as well as an automaton index where to pout the variable |
||||
|
*/ |
||||
|
std::pair<bool, uint64_t> canMakeVariableLocal(storm::expressions::Variable const& variable, Model const& model, std::vector<Property> const& properties = {}, boost::optional<uint64_t> automatonIndex = boost::none) const; |
||||
|
|
||||
|
/*! |
||||
|
* Moves as many variables to the global scope as possible |
||||
|
*/ |
||||
|
void makeVariablesGlobal(Model& model) const; |
||||
|
|
||||
|
/*! |
||||
|
* Moves as many variables to a local scope as possible |
||||
|
*/ |
||||
|
void makeVariablesLocal(Model& model, std::vector<Property> const& properties = {}) const; |
||||
|
|
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue