Storm 1.14.0.1
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
43 STORM_LOG_TRACE("\t\t" + std::to_string(partOfPropCount) + " old locations potentially satisfy property");
44
45 auto &automatonInfo = session.getAutomatonInfo(automatonName);
46
48
49 if (automatonInfo.hasSink) {
50 expander.excludeLocation(automatonInfo.sinkIndex);
51 }
52
53 auto result = expander.transform(automatonName, variableName);
54 session.setModel(result.newModel);
55
56 if (automatonInfo.hasSink) {
57 automatonInfo.sinkIndex = result.newIndices.excludedLocationsToNewIndices[automatonInfo.sinkIndex];
58 }
59
60 // After executing the expander, we can now determine which new locations satisfy the property:
61
62 // First, we check whether the variable is even contained in the property. If not, we can just use the
63 // isPartOfProp values of the old locations.
64 bool variablePartOfProperty = session.isVariablePartOfProperty(expressionVariableName);
65
66 // If we have many locations that potentially satisfy the property, we can try to exploit symmetries. For
67 // example, if the property is a conjunction that contains "testVar = 4" and we're unfolding testVar, we
68 // don't have to check whether testVar = 0 satisfies the property for all locations -- if sufficies to
69 // check once, globally. We store values for which the property is never satisfied in knownUnsatValues:
70 std::set<uint64_t> knownUnsatValues;
71 // If we only have 1 or 2 locations, the overhead of checking globally probably isn't worth it, so only
72 // check if we have at least 3 locations that potentially satisfy the property.
73 if (partOfPropCount >= 3) {
74 std::map<expressions::Variable, expressions::Expression> substitutionMap;
76 for (uint64_t i = 0; i < result.newIndices.variableDomain.size(); i++) {
77 substitutionMap[variable] = result.newIndices.variableDomain[i];
78 bool satisfiesProperty = session.computeIsPartOfProp(substitutionMap);
79 if (!satisfiesProperty) {
80 knownUnsatValues.emplace(i);
81 }
82 }
83 STORM_LOG_TRACE("\t\t" + std::to_string(knownUnsatValues.size()) + " variable values never satisfy property");
84 }
85
86 // If true, this doesn't perform satisfiability checks and instead simply assumes that any location
87 // potentially satisfies the property unless it can be disproven.
88 bool avoidChecks = false;
89 if (partOfPropCount > 5 && automaton.getNumberOfLocations() > partOfPropCount * 5) {
90 avoidChecks = true;
91 }
92
93 // These are just used for statistics:
94 uint64_t knownUnsatCounter = 0;
95 uint64_t satisfactionCheckCounter = 0;
96 uint64_t knownSatCounter = 0;
97 uint64_t oldLocationUnsatCounter = 0;
98
99 for (std::pair<uint64_t, std::map<int64_t, uint64_t>> oldLocMapping : result.newIndices.locationVariableValueMap) {
100 bool oldSatisfied = partOfProp[oldLocMapping.first];
101 for (std::pair<uint64_t, uint64_t> valueIndexPair : oldLocMapping.second) {
102 if (oldSatisfied) {
103 bool isPartOfProp;
104 if (variablePartOfProperty) {
105 if (knownUnsatValues.count(valueIndexPair.first) > 0) {
106 isPartOfProp = false;
107 knownUnsatCounter++;
108 } else {
109 if (avoidChecks) {
110 isPartOfProp = true;
111 } else {
112 isPartOfProp = session.computeIsPartOfProp(automatonName, valueIndexPair.second);
113 }
114 satisfactionCheckCounter++;
115 }
116 } else {
117 // If the variable isn't contained in the property, this location will satisfy the
118 // property, because the old one also did.
119 isPartOfProp = true;
120 knownSatCounter++;
121 }
122 session.setPartOfProp(automatonName, valueIndexPair.second, isPartOfProp);
123 } else {
124 session.setPartOfProp(automatonName, valueIndexPair.second, false);
125 oldLocationUnsatCounter++;
126 }
127 }
128 }
129
130 uint64_t totalCount = knownUnsatCounter + satisfactionCheckCounter + knownSatCounter + oldLocationUnsatCounter;
131 STORM_LOG_TRACE("\t\tPerformed " + std::to_string(satisfactionCheckCounter) + " property satisfaction checks (location count: " +
132 std::to_string(totalCount) + "), avoided\n\t\t\t" + std::to_string(oldLocationUnsatCounter) + " because old location was unsat,\n\t\t\t" +
133 std::to_string(knownSatCounter) + " because variable was not part of property and old location was sat and\n\t\t\t" +
134 std::to_string(knownUnsatCounter) + " because variable value was known to never satisfy property.");
135}
136} // namespace elimination_actions
137} // namespace jani
138} // 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:785
bool hasAutomaton(std::string const &name) const
Rerieves whether there exists an automaton with the given name.
Definition Model.cpp:876
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
Definition Model.cpp:884
UnfoldAction(const std::string &automatonName, const std::string &variableName)
void doAction(JaniLocalEliminator::Session &session) override
#define STORM_LOG_TRACE(message)
Definition logging.h:15
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28