16 : original(original), addMissingGuards(addMissingGuards) {
17 setProperty(property);
22 : original(original), addMissingGuards(addMissingGuards) {
23 if (properties.size() > 1) {
24 STORM_LOG_WARN(
"Only the first property will be used for local elimination.");
26 STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidArgumentException,
"Local elimination requires at least one property.");
28 setProperty(properties[0]);
34 uint64_t edgesHeuristic) {
36 eliminator.scheduler.addAction(std::make_unique<elimination_actions::AutomaticAction>(locationHeuristic, edgesHeuristic));
37 eliminator.eliminate();
38 return eliminator.getResult();
46 if (addMissingGuards) {
51 bool hasTransientAssignments =
false;
52 for (
auto loc : automaton.getLocations()) {
53 if (loc.getAssignments().hasTransientAssignment()) {
54 hasTransientAssignments =
true;
57 if (hasTransientAssignments) {
58 STORM_LOG_TRACE(
"Pushing transient location assignments to edge destinations");
59 automaton.pushTransientRealLocationAssignmentsToEdges();
60 automaton.pushEdgeAssignmentsToDestinations();
65 std::unique_ptr<Action> action =
scheduler.getNextAction();
66 action->doAction(session);
81 Automaton &automaton = model.getAutomaton(automatonName);
85 if (dest.getLocationIndex() == locationIndex) {
93 Automaton &automaton = model.getAutomaton(automatonName);
96 if (!edge.hasSilentAction()) {
104 Automaton &automaton = model.getAutomaton(automatonName);
106 for (
const auto &asg : location.getAssignments()) {
107 if (!asg.isTransient()) {
110 if (asg.getAssignedExpression().containsVariables() ||
111 (asg.getVariable().hasInitExpression() && asg.getVariable().getInitExpression().containsVariables())) {
114 if (asg.getVariable().getType().isBoundedType() && asg.getVariable().getType().asBoundedType().isIntegerType()) {
115 if (asg.getVariable().hasInitExpression()) {
116 int initValue = asg.getVariable().getInitExpression().evaluateAsInt();
117 int currentValue = asg.getAssignedExpression().evaluateAsInt();
118 if (initValue != currentValue) {
122 STORM_LOG_WARN(
"Variable " + asg.getVariable().getName() +
" has no init expression. The result may not be correct.");
124 }
else if (asg.getVariable().getType().isBasicType() && asg.getVariable().getType().asBasicType().isBooleanType()) {
125 if (asg.getVariable().hasInitExpression()) {
126 bool initValue = asg.getVariable().getInitExpression().evaluateAsBool();
127 bool currentValue = asg.getAssignedExpression().evaluateAsBool();
128 if (initValue != currentValue) {
132 STORM_LOG_WARN(
"Variable " + asg.getVariable().getName() +
" has no init expression. The result may not be correct.");
141 uint64_t locationIndex = model.getAutomaton(automatonName).getLocationIndex(locationName);
146 AutomatonInfo &autInfo = automataInfo[automatonName];
147 return autInfo.potentiallyPartOfProp.count(locationIndex) == 1;
151 Automaton &automaton = model.getAutomaton(automatonName);
157 Automaton &automaton = model.getAutomaton(automatonName);
158 auto location = automaton.
getLocation(locationIndex);
159 std::map<expressions::Variable, expressions::Expression> substitutionMap;
160 for (
auto &asg : location.getAssignments()) {
161 if (!asg.isTransient()) {
164 substitutionMap.insert(std::pair<expressions::Variable, expressions::Expression>(asg.getExpressionVariable(), asg.getAssignedExpression()));
171 auto propertyFormula =
property.getRawFormula()->substitute(substitutionMap);
172 auto expression = model.getExpressionManager().boolean(
false);
173 if (propertyFormula->isProbabilityOperatorFormula() || propertyFormula->isRewardOperatorFormula()) {
174 auto subformula = &propertyFormula->asUnaryStateFormula().getSubformula();
175 if (subformula->isEventuallyFormula()) {
176 expression = subformula->asEventuallyFormula().getSubformula().toExpression(model.getExpressionManager());
177 }
else if (subformula->isUntilFormula()) {
178 const auto &untilFormula = subformula->asUntilFormula();
179 if (untilFormula.getLeftSubformula().isTrueFormula() && untilFormula.getRightSubformula().isAtomicExpressionFormula()) {
180 expression = untilFormula.getRightSubformula().toExpression(model.getExpressionManager());
182 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"Until formulas are only supported if the left subformula is \"true\".");
185 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"This type of formula is not supported.");
188 auto simplified = expression.simplify();
189 if (simplified.isLiteral()) {
190 return simplified.evaluateAsBool();
194 auto result =
solver.check();
199 uint64_t locationIndex = model.getAutomaton(automatonName).getLocationIndex(locationName);
204 AutomatonInfo &autInfo = automataInfo[automatonName];
205 if (autInfo.potentiallyPartOfProp.count(locationIndex) == 1) {
207 autInfo.potentiallyPartOfProp.erase(locationIndex);
211 autInfo.potentiallyPartOfProp.insert(locationIndex);
217 AutomatonInfo &autInfo = automataInfo[automatonName];
218 autInfo.potentiallyPartOfProp.clear();
223 bool supported =
false;
225 if (raw->isProbabilityOperatorFormula()) {
226 auto subformula = &raw->asProbabilityOperatorFormula().getSubformula();
227 if (subformula->isEventuallyFormula()) {
229 }
else if (subformula->isUntilFormula()) {
230 const auto &untilFormula = subformula->asUntilFormula();
231 if (untilFormula.getLeftSubformula().isTrueFormula()) {
236 if (raw->isRewardOperatorFormula()) {
237 auto subformula = &raw->asRewardOperatorFormula().getSubformula();
238 if (subformula->isEventuallyFormula()) {
240 }
else if (subformula->isUntilFormula()) {
241 const auto &untilFormula = subformula->asUntilFormula();
242 if (untilFormula.getLeftSubformula().isTrueFormula()) {
248 STORM_LOG_THROW(supported, storm::exceptions::NotSupportedException,
"This type of property is not supported for location elimination.");
250 this->
property = newProperty;
256 if (actionQueue.empty()) {
257 return std::make_unique<elimination_actions::FinishAction>();
259 std::unique_ptr<JaniLocalEliminator::Action> val = std::move(actionQueue.front());
265 actionQueue.push(std::move(action));
269 if (flatten && model.getNumberOfAutomata() > 1) {
275 if (property.getRawFormula()->isRewardOperatorFormula()) {
276 isRewardFormula = true;
277 rewardModels = property.getRawFormula()->getReferencedRewardModels();
278 }
else if (property.getRawFormula()->isProbabilityOperatorFormula()) {
279 isRewardFormula = false;
281 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException,
"This type of property is currently not supported.");
284 for (
auto &var : property.getUsedVariablesAndConstants()) {
285 expressionVarsInProperty.insert(var.getIndex());
306 this->finished = finished;
319 std::set<std::string> &rewardVariables) {
321 "Assignment levels are currently not supported.");
330 std::set<expressions::Variable> thenVariables;
332 thenVariables.emplace(assignment.getExpressionVariable());
337 if (thenVariables.find(assignment.getExpressionVariable()) != thenVariables.end()) {
340 newOa.
add(assignment);
347 bool isReward = rewardVariables.count(assignment.getExpressionVariable().getName());
348 auto firstAssignment = substitutionMap.find(assignment.getExpressionVariable());
349 if (isReward && firstAssignment != substitutionMap.end()) {
350 auto newAssignment = firstAssignment->second + assignment.getAssignedExpression().substitute(substitutionMap);
352 newOa.
add(
Assignment(assignment.getVariable(), newAssignment));
354 newOa.
add(
Assignment(assignment.getVariable(), assignment.getAssignedExpression().substitute(substitutionMap).simplify()));
361 auto expressionVariable = model.getExpressionManager().getVariable(expressionVariableName);
362 uint_fast64_t expressionVariableIndex = expressionVariable.getIndex();
363 return expressionVarsInProperty.count(expressionVariableIndex) != 0;
367 model = model.flattenComposition();
368 automataInfo.
clear();
373 auto &automaton = model.getAutomaton(automatonName);
375 std::string sinkName =
"sink_location";
376 while (automaton.hasLocation(sinkName)) {
380 automaton.addLocation(sink);
381 uint64_t sinkIndex = automaton.getNumberOfLocations() - 1;
383 automataInfo[automatonName].hasSink =
true;
384 automataInfo[automatonName].sinkIndex = sinkIndex;
386 for (uint64_t i = 0; i < automaton.getNumberOfLocations(); i++) {
387 if (i == sinkIndex) {
390 auto outgoingEdges = automaton.getEdgesFromLocation(i);
392 allGuards = model.getExpressionManager().boolean(
false);
393 for (
const auto &edge : outgoingEdges) {
394 allGuards = edge.getGuard() || allGuards;
402 for (
const auto &var : model.getGlobalVariables()) {
403 if (var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType() && variables.count(var.getExpressionVariable()) > 0) {
404 auto &biVariable = var.getType().asBoundedType();
405 solver.add(var.getExpressionVariable().getExpression() >= biVariable.getLowerBound());
406 solver.add(var.getExpressionVariable().getExpression() <= biVariable.getUpperBound());
409 for (
const auto &var : automaton.getVariables()) {
410 if (var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType() && variables.count(var.getExpressionVariable()) > 0) {
411 auto &biVariable = var.getType().asBoundedType();
412 solver.add(var.getExpressionVariable().getExpression() >= biVariable.getLowerBound());
413 solver.add(var.getExpressionVariable().getExpression() <= biVariable.getUpperBound());
416 auto result =
solver.check();
419 STORM_LOG_TRACE(
"\tAdding missing guard from location " + automaton.getLocation(i).getName());
423 auto satisfyingAssignment =
solver.getModel();
425 for (
auto &var : variables) {
426 if (var.hasIntegerType()) {
427 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getIntegerValue(var));
428 }
else if (var.hasBooleanType()) {
429 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getBooleanValue(var));
430 }
else if (var.hasRationalType()) {
431 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getRationalValue(var));
437 STORM_LOG_TRACE(
"\t\tThe solver could not determine whether the guard was satisfiable");
439 std::vector<std::pair<uint64_t, storm::expressions::Expression>> destinationLocationsAndProbabilities;
440 std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(newGuard);
442 templateEdge->addDestination(ted);
443 destinationLocationsAndProbabilities.emplace_back(sinkIndex, model.getExpressionManager().rational(1.0));
445 automaton.addEdge(
storm::jani::Edge(i, 0, boost::none, templateEdge, destinationLocationsAndProbabilities));
447 STORM_LOG_TRACE(
"\tLocation " + automaton.getLocation(i).getName() +
" has no missing guard");
453 for (
auto &aut : model.getAutomata()) {
454 automataInfo[aut.getName()] = AutomatonInfo();
455 for (
auto &loc : aut.getLocations()) {
463 return automataInfo[name];
466JaniLocalEliminator::AutomatonInfo::AutomatonInfo() : hasSink(false), sinkIndex(0) {}
Expression simplify() const
Simplifies the expression according to some basic rules.
std::set< storm::expressions::Variable > getVariables() const
Retrieves the set of all variables that appear in the expression.
Expression substitute(std::map< Variable, Expression > const &variableToExpressionMap) const
Substitutes all occurrences of the variables according to the given map.
Location const & getLocation(uint64_t index) const
Retrieves the location with the given index.
Edges getEdgesFromLocation(std::string const &name)
Retrieves the edges of the location with the given name.
std::string const & getName() const
Retrieves the name of the automaton.
uint64_t getLocationIndex(std::string const &name) const
std::map< storm::expressions::Variable, storm::expressions::Expression > getAsVariableToExpressionMap() const
Retrieves the mapping from variables to their assigned expressions that corresponds to the assignment...
bool usesAssignmentLevels() const
Retrieves whether the edge uses an assignment level other than zero.
storm::expressions::Expression const & getProbability() const
Retrieves the probability of choosing this destination.
OrderedAssignments const & getOrderedAssignments() const
Retrieves the assignments to make when choosing this destination.
storm::expressions::Expression const & getGuard() const
Retrieves the guard of this edge.
void addAction(std::unique_ptr< Action > action)
std::unique_ptr< Action > getNextAction()
bool computeIsPartOfProp(const std::string &automatonName, const std::string &locationName)
Session(Model model, Property property, bool flatten=true)
expressions::Expression getNewGuard(const Edge &edge, const EdgeDestination &dest, const Edge &outgoing)
bool hasLoops(const std::string &automatonName, std::string const &locationName)
void setPartOfProp(const std::string &automatonName, const std::string &locationName, bool isPartOfProp)
expressions::Expression getProbability(const EdgeDestination &first, const EdgeDestination &then)
bool hasNamedActions(const std::string &automatonName, std::string const &locationName)
bool isPartOfProp(const std::string &automatonName, std::string const &locationName)
bool isPossiblyInitial(const std::string &automatonName, std::string const &locationName)
bool isVariablePartOfProperty(const std::string &expressionVariableName)
void addMissingGuards(const std::string &automatonName)
void setFinished(bool finished)
AutomatonInfo & getAutomatonInfo(const std::string &name)
void clearIsPartOfProp(const std::string &automatonName)
bool isEliminable(const std::string &automatonName, std::string const &locationName)
OrderedAssignments executeInSequence(const EdgeDestination &first, const EdgeDestination &then, std::set< std::string > &rewardVariables)
void setModel(const Model &model)
void eliminate(bool flatten=true)
Model const & getResult()
static Model eliminateAutomatically(const Model &model, std::vector< jani::Property > properties, uint64_t locationHeuristic, uint64_t edgesHeuristic)
EliminationScheduler scheduler
JaniLocalEliminator(Model const &original, storm::jani::Property &property, bool addMissingGuards=false)
std::vector< Automaton > & getAutomata()
Retrieves the automata of the model.
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
void finalize()
After adding all components to the model, this method has to be called.
void clear()
Removes all assignments from this set.
bool add(Assignment const &assignment, bool addToExisting=false)
Adds the given assignment to the set of assignments.
std::shared_ptr< storm::logic::Formula const > getRawFormula() const
#define STORM_LOG_WARN(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_THROW(cond, exception, message)