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();
66 action->doAction(session);
81 Automaton &automaton = model.getAutomaton(automatonName);
85 if (dest.getLocationIndex() == locationIndex)
92 Automaton &automaton = model.getAutomaton(automatonName);
95 if (!edge.hasSilentAction()) {
103 Automaton &automaton = model.getAutomaton(automatonName);
105 for (
const auto &asg : location.getAssignments()) {
106 if (!asg.isTransient())
108 if (asg.getAssignedExpression().containsVariables() ||
109 (asg.getVariable().hasInitExpression() && asg.getVariable().getInitExpression().containsVariables()))
111 if (asg.getVariable().getType().isBoundedType() && asg.getVariable().getType().asBoundedType().isIntegerType()) {
112 if (asg.getVariable().hasInitExpression()) {
113 int initValue = asg.getVariable().getInitExpression().evaluateAsInt();
114 int currentValue = asg.getAssignedExpression().evaluateAsInt();
115 if (initValue != currentValue)
118 STORM_LOG_WARN(
"Variable " + asg.getVariable().getName() +
" has no init expression. The result may not be correct.");
120 }
else if (asg.getVariable().getType().isBasicType() && asg.getVariable().getType().asBasicType().isBooleanType()) {
121 if (asg.getVariable().hasInitExpression()) {
122 bool initValue = asg.getVariable().getInitExpression().evaluateAsBool();
123 bool currentValue = asg.getAssignedExpression().evaluateAsBool();
124 if (initValue != currentValue)
127 STORM_LOG_WARN(
"Variable " + asg.getVariable().getName() +
" has no init expression. The result may not be correct.");
136 uint64_t locationIndex = model.getAutomaton(automatonName).getLocationIndex(locationName);
137 return isPartOfProp(automatonName, locationIndex);
141 AutomatonInfo &autInfo = automataInfo[automatonName];
142 return autInfo.potentiallyPartOfProp.count(locationIndex) == 1;
146 Automaton &automaton = model.getAutomaton(automatonName);
148 return computeIsPartOfProp(automatonName, locationIndex);
152 Automaton &automaton = model.getAutomaton(automatonName);
153 auto location = automaton.
getLocation(locationIndex);
154 std::map<expressions::Variable, expressions::Expression> substitutionMap;
155 for (
auto &asg : location.getAssignments()) {
156 if (!asg.isTransient())
158 substitutionMap.insert(std::pair<expressions::Variable, expressions::Expression>(asg.getExpressionVariable(), asg.getAssignedExpression()));
160 return computeIsPartOfProp(substitutionMap);
165 auto propertyFormula =
property.getRawFormula()->substitute(substitutionMap);
166 auto expression = model.getExpressionManager().boolean(
false);
167 if (propertyFormula->isProbabilityOperatorFormula() || propertyFormula->isRewardOperatorFormula()) {
168 auto subformula = &propertyFormula->asUnaryStateFormula().getSubformula();
169 if (subformula->isEventuallyFormula()) {
170 expression = subformula->asEventuallyFormula().getSubformula().toExpression(model.getExpressionManager());
171 }
else if (subformula->isUntilFormula()) {
172 const auto &untilFormula = subformula->asUntilFormula();
173 if (untilFormula.getLeftSubformula().isTrueFormula() && untilFormula.getRightSubformula().isAtomicExpressionFormula()) {
174 expression = untilFormula.getRightSubformula().toExpression(model.getExpressionManager());
176 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"Until formulas are only supported if the left subformula is \"true\"");
179 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"This type of formula is not supported");
182 auto simplified = expression.simplify();
183 if (simplified.isLiteral()) {
184 return simplified.evaluateAsBool();
186 solver.
add(simplified);
188 auto result = solver.
check();
193 uint64_t locationIndex = model.getAutomaton(automatonName).getLocationIndex(locationName);
194 return setPartOfProp(automatonName, locationIndex, isPartOfProp);
198 AutomatonInfo &autInfo = automataInfo[automatonName];
199 if (autInfo.potentiallyPartOfProp.count(locationIndex) == 1) {
201 autInfo.potentiallyPartOfProp.erase(locationIndex);
205 autInfo.potentiallyPartOfProp.insert(locationIndex);
211 AutomatonInfo &autInfo = automataInfo[automatonName];
212 autInfo.potentiallyPartOfProp.clear();
217 bool supported =
false;
219 if (raw->isProbabilityOperatorFormula()) {
220 auto subformula = &raw->asProbabilityOperatorFormula().getSubformula();
221 if (subformula->isEventuallyFormula()) {
223 }
else if (subformula->isUntilFormula()) {
224 const auto &untilFormula = subformula->asUntilFormula();
225 if (untilFormula.getLeftSubformula().isTrueFormula()) {
230 if (raw->isRewardOperatorFormula()) {
231 auto subformula = &raw->asRewardOperatorFormula().getSubformula();
232 if (subformula->isEventuallyFormula()) {
234 }
else if (subformula->isUntilFormula()) {
235 const auto &untilFormula = subformula->asUntilFormula();
236 if (untilFormula.getLeftSubformula().isTrueFormula()) {
242 STORM_LOG_THROW(supported, storm::exceptions::NotSupportedException,
"This type of property is not supported for location elimination");
244 this->
property = newProperty;
250 if (actionQueue.empty()) {
251 return std::make_unique<elimination_actions::FinishAction>();
253 std::unique_ptr<JaniLocalEliminator::Action> val = std::move(actionQueue.front());
259 actionQueue.push(std::move(action));
271 rewardModels =
property.getRawFormula()->getReferencedRewardModels();
272 }
else if (property.
getRawFormula()->isProbabilityOperatorFormula()) {
275 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"This type of property is currently not supported");
278 for (
auto &var :
property.getUsedVariablesAndConstants()) {
279 expressionVarsInProperty.insert(var.getIndex());
300 this->finished = finished;
313 std::set<std::string> &rewardVariables) {
315 "Assignment levels are currently not supported");
324 std::set<expressions::Variable> thenVariables;
326 thenVariables.emplace(assignment.getExpressionVariable());
331 if (thenVariables.find(assignment.getExpressionVariable()) != thenVariables.end()) {
334 newOa.
add(assignment);
341 bool isReward = rewardVariables.count(assignment.getExpressionVariable().getName());
342 auto firstAssignment = substitutionMap.find(assignment.getExpressionVariable());
343 if (isReward && firstAssignment != substitutionMap.end()) {
344 auto newAssignment = (*firstAssignment).second + assignment.getAssignedExpression().substitute(substitutionMap);
346 newOa.
add(
Assignment(assignment.getVariable(), newAssignment));
348 newOa.
add(
Assignment(assignment.getVariable(), assignment.getAssignedExpression().substitute(substitutionMap).simplify()));
355 auto expressionVariable = model.getExpressionManager().getVariable(expressionVariableName);
356 uint_fast64_t expressionVariableIndex = expressionVariable.getIndex();
357 return expressionVarsInProperty.count(expressionVariableIndex) != 0;
361 model = model.flattenComposition();
362 automataInfo.
clear();
367 auto &automaton = model.getAutomaton(automatonName);
369 std::string sinkName =
"sink_location";
370 while (automaton.hasLocation(sinkName)) {
374 automaton.addLocation(sink);
375 uint64_t sinkIndex = automaton.getNumberOfLocations() - 1;
377 automataInfo[automatonName].hasSink =
true;
378 automataInfo[automatonName].sinkIndex = sinkIndex;
380 for (uint64_t i = 0; i < automaton.getNumberOfLocations(); i++) {
383 auto outgoingEdges = automaton.getEdgesFromLocation(i);
385 allGuards = model.getExpressionManager().boolean(
false);
386 for (
const auto &edge : outgoingEdges) {
387 allGuards = edge.getGuard() || allGuards;
394 solver.
add(newGuard);
395 for (
const auto &var : model.getGlobalVariables()) {
396 if (var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType() && variables.count(var.getExpressionVariable()) > 0) {
397 auto &biVariable = var.getType().asBoundedType();
398 solver.
add(var.getExpressionVariable().getExpression() >= biVariable.getLowerBound());
399 solver.
add(var.getExpressionVariable().getExpression() <= biVariable.getUpperBound());
402 for (
const auto &var : automaton.getVariables()) {
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 auto result = solver.
check();
412 STORM_LOG_TRACE(
"\tAdding missing guard from location " + automaton.getLocation(i).getName());
416 auto satisfyingAssignment = solver.
getModel();
418 for (
auto &var : variables) {
419 if (var.hasIntegerType()) {
420 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getIntegerValue(var));
421 }
else if (var.hasBooleanType()) {
422 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getBooleanValue(var));
423 }
else if (var.hasRationalType()) {
424 message +=
"\t\t\t" + var.getName() +
": " + std::to_string(satisfyingAssignment->getRationalValue(var));
430 STORM_LOG_TRACE(
"\t\tThe solver could not determine whether the guard was satisfiable");
432 std::vector<std::pair<uint64_t, storm::expressions::Expression>> destinationLocationsAndProbabilities;
433 std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(newGuard);
435 templateEdge->addDestination(ted);
436 destinationLocationsAndProbabilities.emplace_back(sinkIndex, model.getExpressionManager().rational(1.0));
438 automaton.addEdge(
storm::jani::Edge(i, 0, boost::none, templateEdge, destinationLocationsAndProbabilities));
440 STORM_LOG_TRACE(
"\tLocation " + automaton.getLocation(i).getName() +
" has no missing guard");
446 for (
auto &aut : model.getAutomata()) {
447 automataInfo[aut.getName()] = AutomatonInfo();
448 for (
auto &loc : aut.getLocations()) {
449 bool isPartOfProp = computeIsPartOfProp(aut.getName(), loc.getName());
450 setPartOfProp(aut.getName(), loc.getName(), isPartOfProp);
456 return automataInfo[name];
459JaniLocalEliminator::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)
std::set< std::string > rewardModels
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.
std::size_t getNumberOfAutomata() const
Retrieves the number of automata in this 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
virtual void add(storm::expressions::Expression const &assertion) override
Adds an assertion to the solver's stack.
virtual std::shared_ptr< SmtSolver::ModelReference > getModel() override
If the last call to check() or checkWithAssumptions() returned Sat, this method retrieves a model tha...
virtual CheckResult check() override
Checks whether the conjunction of assertions that are currently on the solver's stack is satisfiable.
#define STORM_LOG_WARN(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_THROW(cond, exception, message)