Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
UnfoldAction.cpp
Go to the documentation of this file.
1#include "UnfoldAction.h"
2#include <boost/format.hpp>
5
6namespace storm {
7namespace jani {
8namespace elimination_actions {
9UnfoldAction::UnfoldAction(const std::string &automatonName, const std::string &variableName) {
10 this->automatonName = automatonName;
11 this->variableName = variableName;
13}
14UnfoldAction::UnfoldAction(const std::string &automatonName, const std::string &janiVariableName, const std::string &expressionVariableName) {
15 this->automatonName = automatonName;
16 this->variableName = janiVariableName;
17 this->expressionVariableName = expressionVariableName;
18}
19
21 return (boost::format("UnfoldAction (Automaton %s, Variable %s)") % automatonName % variableName).str();
22}
23
25 // In addition to doing the unfolding, we also need to update which location might satisfy the property.
26 // If a location that doesn't satisfy the property is unfolded, all resulting locations also won't
27 // satisfy it. We therefore first store which old locations satisfy the property:
28
29 STORM_LOG_THROW(session.getModel().hasAutomaton(automatonName), storm::exceptions::IllegalArgumentException,
30 "Cannot find automaton with name " << automatonName);
31
32 uint64_t partOfPropCount = 0;
33
34 std::map<uint64_t, bool> partOfProp;
35 auto automaton = session.getModel().getAutomaton(automatonName);
36 for (uint64_t i = 0; i < automaton.getNumberOfLocations(); i++) {
37 partOfProp[i] = session.isPartOfProp(automatonName, i);
38 if (partOfProp[i])
39 partOfPropCount += 1;
40 }
41
42 STORM_LOG_TRACE("\t\t" + std::to_string(partOfPropCount) + " old locations potentially satisfy property");
43
44 auto &automatonInfo = session.getAutomatonInfo(automatonName);
45
47
48 if (automatonInfo.hasSink) {
49 expander.excludeLocation(automatonInfo.sinkIndex);
50 }
51
52 auto result = expander.transform(automatonName, variableName);
53 session.setModel(result.newModel);
54
55 if (automatonInfo.hasSink) {
56 automatonInfo.sinkIndex = result.newIndices.excludedLocationsToNewIndices[automatonInfo.sinkIndex];
57 }
58
59 // After executing the expander, we can now determine which new locations satisfy the property:
60
61 // First, we check whether the variable is even contained in the property. If not, we can just use the
62 // isPartOfProp values of the old locations.
63 bool variablePartOfProperty = session.isVariablePartOfProperty(expressionVariableName);
64
65 // If we have many locations that potentially satisfy the property, we can try to exploit symmetries. For
66 // example, if the property is a conjunction that contains "testVar = 4" and we're unfolding testVar, we
67 // don't have to check whether testVar = 0 satisfies the property for all locations -- if sufficies to
68 // check once, globally. We store values for which the property is never satisfied in knownUnsatValues:
69 std::set<uint64_t> knownUnsatValues;
70 // If we only have 1 or 2 locations, the overhead of checking globally probably isn't worth it, so only
71 // check if we have at least 3 locations that potentially satisfy the property.
72 if (partOfPropCount >= 3) {
73 std::map<expressions::Variable, expressions::Expression> substitutionMap;
75 for (uint64_t i = 0; i < result.newIndices.variableDomain.size(); i++) {
76 substitutionMap[variable] = result.newIndices.variableDomain[i];
77 bool satisfiesProperty = session.computeIsPartOfProp(substitutionMap);
78 if (!satisfiesProperty) {
79 knownUnsatValues.emplace(i);
80 }
81 }
82 STORM_LOG_TRACE("\t\t" + std::to_string(knownUnsatValues.size()) + " variable values never satisfy property");
83 }
84
85 // If true, this doesn't perform satisfiability checks and instead simply assumes that any location
86 // potentially satisfies the property unless it can be disproven.
87 bool avoidChecks = false;
88 if (partOfPropCount > 5 && automaton.getNumberOfLocations() > partOfPropCount * 5) {
89 avoidChecks = true;
90 }
91
92 // These are just used for statistics:
93 uint64_t knownUnsatCounter = 0;
94 uint64_t satisfactionCheckCounter = 0;
95 uint64_t knownSatCounter = 0;
96 uint64_t oldLocationUnsatCounter = 0;
97
98 for (std::pair<uint64_t, std::map<int64_t, uint64_t>> oldLocMapping : result.newIndices.locationVariableValueMap) {
99 bool oldSatisfied = partOfProp[oldLocMapping.first];
100 for (std::pair<uint64_t, uint64_t> valueIndexPair : oldLocMapping.second) {
101 if (oldSatisfied) {
102 bool isPartOfProp;
103 if (variablePartOfProperty) {
104 if (knownUnsatValues.count(valueIndexPair.first) > 0) {
105 isPartOfProp = false;
106 knownUnsatCounter++;
107 } else {
108 if (avoidChecks) {
109 isPartOfProp = true;
110 } else {
111 isPartOfProp = session.computeIsPartOfProp(automatonName, valueIndexPair.second);
112 }
113 satisfactionCheckCounter++;
114 }
115 } else {
116 // If the variable isn't contained in the property, this location will satisfy the
117 // property, because the old one also did.
118 isPartOfProp = true;
119 knownSatCounter++;
120 }
121 session.setPartOfProp(automatonName, valueIndexPair.second, isPartOfProp);
122 } else {
123 session.setPartOfProp(automatonName, valueIndexPair.second, false);
124 oldLocationUnsatCounter++;
125 }
126 }
127 }
128
129 uint64_t totalCount = knownUnsatCounter + satisfactionCheckCounter + knownSatCounter + oldLocationUnsatCounter;
130 STORM_LOG_TRACE("\t\tPerformed " + std::to_string(satisfactionCheckCounter) + " property satisfaction checks (location count: " +
131 std::to_string(totalCount) + "), avoided\n\t\t\t" + std::to_string(oldLocationUnsatCounter) + " because old location was unsat,\n\t\t\t" +
132 std::to_string(knownSatCounter) + " because variable was not part of property and old location was sat and\n\t\t\t" +
133 std::to_string(knownUnsatCounter) + " because variable value was known to never satisfy property.");
134}
135} // namespace elimination_actions
136} // namespace jani
137} // namespace storm
Variable getVariable(std::string const &name) const
Retrieves the expression that represents the variable with the given name.
bool computeIsPartOfProp(const std::string &automatonName, const std::string &locationName)
void setPartOfProp(const std::string &automatonName, const std::string &locationName, bool isPartOfProp)
bool isPartOfProp(const std::string &automatonName, std::string const &locationName)
bool isVariablePartOfProperty(const std::string &expressionVariableName)
AutomatonInfo & getAutomatonInfo(const std::string &name)
ReturnType transform(std::string const &automatonName, std::string const &variableName)
storm::expressions::ExpressionManager & getExpressionManager() const
Retrieves the manager responsible for the expressions in the JANI model.
Definition Model.cpp:789
bool hasAutomaton(std::string const &name) const
Rerieves whether there exists an automaton with the given name.
Definition Model.cpp:880
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
Definition Model.cpp:888
UnfoldAction(const std::string &automatonName, const std::string &variableName)
void doAction(JaniLocalEliminator::Session &session) override
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
LabParser.cpp.
Definition cli.cpp:18