Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JaniMenuGameAbstractor.cpp
Go to the documentation of this file.
2
6
8
12
15
17
19
24#include "storm/utility/dd.h"
27
28#include "storm-config.h"
30
31namespace storm::gbar {
32namespace abstraction {
33namespace jani {
34
36
37template<storm::dd::DdType DdType, typename ValueType>
39 std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory,
40 MenuGameAbstractorOptions const& options)
41 : model(model),
42 smtSolverFactory(smtSolverFactory),
43 abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager()),
44 AbstractionInformationOptions(options.constraints)),
45 automata(),
46 initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory),
47 restrictToValidBlocks(false),
48 validBlockAbstractor(abstractionInformation, smtSolverFactory),
49 currentGame(nullptr),
50 refinementPerformed(true) {
51 // Check whether the model is linear as the abstraction requires this.
52 STORM_LOG_WARN_COND(model.isLinear(), "The model appears to contain non-linear expressions, which may cause malfunctioning of the abstraction.");
53
54 // For now, we assume that there is a single module. If the program has more than one module, it needs
55 // to be flattened before the procedure.
56 STORM_LOG_THROW(model.getNumberOfAutomata() == 1, storm::exceptions::WrongFormatException,
57 "Cannot create abstract model from program containing more than one automaton.");
58
59 // Add all variables range expressions to the information object.
60 for (auto const& range : this->model.get().getAllRangeExpressions()) {
61 abstractionInformation.addConstraint(range);
62 initialStateAbstractor.constrain(range);
63 validBlockAbstractor.constrain(range);
64 }
65
66 uint_fast64_t totalNumberOfEdges = 0;
67 uint_fast64_t maximalDestinationCount = 0;
68 std::vector<storm::expressions::Expression> allGuards;
69 for (auto const& automaton : model.getAutomata()) {
70 for (auto const& edge : automaton.getEdges()) {
71 maximalDestinationCount = std::max(maximalDestinationCount, static_cast<uint_fast64_t>(edge.getNumberOfDestinations()));
72 }
73
74 totalNumberOfEdges += automaton.getNumberOfEdges();
75 }
76
77 // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible
78 // choices. If for some reason this should not be enough, we could grow this vector dynamically, but
79 // odds are that it's impossible to treat such models in any event.
80 abstractionInformation.createEncodingVariables(static_cast<uint_fast64_t>(std::ceil(std::log2(totalNumberOfEdges))), 64,
81 static_cast<uint_fast64_t>(std::ceil(std::log2(maximalDestinationCount))));
82
83 // For each module of the concrete program, we create an abstract counterpart.
85 bool useDecomposition = settings.isUseDecompositionSet();
86 restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration;
87 bool addPredicatesForValidBlocks = !restrictToValidBlocks;
88 bool debug = settings.isDebugSet();
89 for (auto const& automaton : model.getAutomata()) {
90 automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug);
91 }
92
93 // Retrieve global BDDs/ADDs so we can multiply them in the abstraction process.
94 initialLocationsBdd = automata.front().getInitialLocationsBdd();
95 edgeDecoratorAdd = automata.front().getEdgeDecoratorAdd();
96}
97
98template<storm::dd::DdType DdType, typename ValueType>
100 return abstractionInformation.getDdManager();
101}
102
103template<storm::dd::DdType DdType, typename ValueType>
105 // Add the predicates to the global list of predicates and gather their indices.
106 std::vector<uint_fast64_t> predicateIndices;
107 for (auto const& predicate : command.getPredicates()) {
108 STORM_LOG_THROW(predicate.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expecting a predicate of type bool.");
109 predicateIndices.push_back(abstractionInformation.getOrAddPredicate(predicate));
110 }
111
112 // Refine all abstract automata.
113 for (auto& automaton : automata) {
114 automaton.refine(predicateIndices);
115 }
116
117 // Refine initial state abstractor.
118 initialStateAbstractor.refine(predicateIndices);
119
120 if (this->restrictToValidBlocks) {
121 // Refine the valid blocks.
122 validBlockAbstractor.refine(predicateIndices);
123 }
124
125 refinementPerformed |= !command.getPredicates().empty();
126}
127
128template<storm::dd::DdType DdType, typename ValueType>
130 if (refinementPerformed) {
131 currentGame = buildGame();
132 refinementPerformed = false;
133 }
134 return *currentGame;
135}
136
137template<storm::dd::DdType DdType, typename ValueType>
141
142template<storm::dd::DdType DdType, typename ValueType>
144 return automata.front().getGuard(player1Choice);
145}
146
147template<storm::dd::DdType DdType, typename ValueType>
149 return automata.front().getNumberOfUpdates(player1Choice);
150}
151
152template<storm::dd::DdType DdType, typename ValueType>
153std::map<storm::expressions::Variable, storm::expressions::Expression> JaniMenuGameAbstractor<DdType, ValueType>::getVariableUpdates(
154 uint64_t player1Choice, uint64_t auxiliaryChoice) const {
155 return automata.front().getVariableUpdates(player1Choice, auxiliaryChoice);
156}
157
158template<storm::dd::DdType DdType, typename ValueType>
159std::set<storm::expressions::Variable> const& JaniMenuGameAbstractor<DdType, ValueType>::getAssignedVariables(uint64_t player1Choice) const {
160 return automata.front().getAssignedVariables(player1Choice);
161}
162
163template<storm::dd::DdType DdType, typename ValueType>
165 return std::make_pair(0, automata.front().getNumberOfEdges());
166}
167
168template<storm::dd::DdType DdType, typename ValueType>
170 return model.get().getInitialStatesExpression({model.get().getAutomaton(0)});
171}
172
173template<storm::dd::DdType DdType, typename ValueType>
175 storm::gbar::abstraction::ExpressionTranslator<DdType> translator(abstractionInformation,
176 smtSolverFactory->create(abstractionInformation.getExpressionManager()));
177 return translator.translate(expression);
178}
179
180template<storm::dd::DdType DdType, typename ValueType>
181std::unique_ptr<MenuGame<DdType, ValueType>> JaniMenuGameAbstractor<DdType, ValueType>::buildGame() {
182 // As long as there is only one automaton, we only build its game representation.
183 GameBddResult<DdType> game = automata.front().abstract();
184
185 // Add the locations to the transitions.
186 game.bdd &= edgeDecoratorAdd.notZero();
187
188 // Construct a set of all unnecessary variables, so we can abstract from it.
189 std::set<storm::expressions::Variable> variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount()));
190 std::set<storm::expressions::Variable> successorAndAuxVariables(abstractionInformation.getSuccessorVariables());
191 auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables);
192 variablesToAbstract.insert(player2Variables.begin(), player2Variables.end());
193 auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount());
194 variablesToAbstract.insert(auxVariables.begin(), auxVariables.end());
195 successorAndAuxVariables.insert(auxVariables.begin(), auxVariables.end());
196
197 storm::utility::Stopwatch relevantStatesWatch(true);
198 storm::dd::Bdd<DdType> nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne();
199 if (this->isRestrictToRelevantStatesSet()) {
200 // Compute which states are non-terminal.
201 for (auto const& expression : this->terminalStateExpressions) {
202 nonTerminalStates &= !this->getStates(expression);
203 }
204 if (this->hasTargetStateExpression()) {
205 nonTerminalStates &= !this->getStates(this->getTargetStateExpression());
206 }
207 }
208 relevantStatesWatch.stop();
209
210 storm::dd::Bdd<DdType> extendedTransitionRelation = nonTerminalStates && game.bdd;
211 storm::dd::Bdd<DdType> initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates();
212 if (this->restrictToValidBlocks) {
213 STORM_LOG_DEBUG("Restricting to valid blocks.");
214 storm::dd::Bdd<DdType> validBlocks = validBlockAbstractor.getValidBlocks();
215
216 // Compute the choices with only valid successors so we can restrict the game to these.
217 auto choicesWithOnlyValidSuccessors =
218 !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) &&
219 game.bdd.existsAbstract(successorAndAuxVariables);
220
221 // Restrict the proper parts.
222 extendedTransitionRelation &= validBlocks && choicesWithOnlyValidSuccessors;
223 initialStates &= validBlocks;
224 }
225
226 // Do a reachability analysis on the raw transition relation.
227 storm::dd::Bdd<DdType> transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract);
228 initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables());
229 storm::dd::Bdd<DdType> reachableStates =
230 storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(),
231 abstractionInformation.getSuccessorVariables())
232 .first;
233
234 relevantStatesWatch.start();
235 if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) {
236 // Get the target state BDD.
237 storm::dd::Bdd<DdType> targetStates = reachableStates && this->getStates(this->getTargetStateExpression());
238
239 // In the presence of target states, we keep only states that can reach the target states.
241 targetStates, reachableStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables());
242
243 // Include all successors of reachable states, because the backward search otherwise potentially
244 // cuts probability 0 choices of these states.
245 reachableStates |=
246 (reachableStates && !targetStates)
247 .relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables());
248
249 // Restrict transition relation to relevant fragment for computation of deadlock states.
250 transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs());
251
252 relevantStatesWatch.stop();
253 STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms.");
254 }
255
256 // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states,
257 // as the bottom states are not contained in the reachable states.
258 storm::dd::Bdd<DdType> deadlockStates = transitionRelation.existsAbstract(abstractionInformation.getSuccessorVariables());
259 deadlockStates = reachableStates && !deadlockStates;
260
261 // If there are deadlock states, we fix them now.
262 storm::dd::Add<DdType, ValueType> deadlockTransitions = abstractionInformation.getDdManager().template getAddZero<ValueType>();
263 if (!deadlockStates.isZero()) {
264 deadlockTransitions = (deadlockStates && abstractionInformation.getAllPredicateIdentities() && abstractionInformation.getAllLocationIdentities() &&
265 abstractionInformation.encodePlayer1Choice(0, abstractionInformation.getPlayer1VariableCount()) &&
266 abstractionInformation.encodePlayer2Choice(0, 0, game.numberOfPlayer2Variables) &&
267 abstractionInformation.encodeAux(0, 0, abstractionInformation.getAuxVariableCount()))
268 .template toAdd<ValueType>();
269 }
270
271 // Compute bottom states and the appropriate transitions if necessary.
272 BottomStateResult<DdType> bottomStateResult(abstractionInformation.getDdManager().getBddZero(), abstractionInformation.getDdManager().getBddZero());
273 bottomStateResult = automata.front().getBottomStateTransitions(reachableStates, game.numberOfPlayer2Variables);
274 bool hasBottomStates = !bottomStateResult.states.isZero();
275
276 // Construct the transition matrix by cutting away the transitions of unreachable states.
277 // Note that we also restrict the successor states of transitions, because there might be successors
278 // that are not in the set of relevant states we restrict to.
279 storm::dd::Add<DdType, ValueType> transitionMatrix =
280 (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()))
281 .template toAdd<ValueType>();
282 transitionMatrix *= edgeDecoratorAdd;
283 transitionMatrix += deadlockTransitions;
284
285 // Extend the current game information with the 'non-bottom' tag before potentially adding bottom state transitions.
286 transitionMatrix *=
287 (abstractionInformation.getBottomStateBdd(true, true) && abstractionInformation.getBottomStateBdd(false, true)).template toAdd<ValueType>();
288 reachableStates &= abstractionInformation.getBottomStateBdd(true, true);
289 initialStates &= abstractionInformation.getBottomStateBdd(true, true);
290
291 // If there are bottom transitions, exnted the transition matrix and reachable states now.
292 if (hasBottomStates) {
293 transitionMatrix += bottomStateResult.transitions.template toAdd<ValueType>();
294 reachableStates |= bottomStateResult.states;
295 }
296
297 std::set<storm::expressions::Variable> allNondeterminismVariables = player2Variables;
298 allNondeterminismVariables.insert(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end());
299
300 std::set<storm::expressions::Variable> allSourceVariables(abstractionInformation.getSourceVariables());
301 allSourceVariables.insert(abstractionInformation.getBottomStateVariable(true));
302 std::set<storm::expressions::Variable> allSuccessorVariables(abstractionInformation.getSuccessorVariables());
303 allSuccessorVariables.insert(abstractionInformation.getBottomStateVariable(false));
304
305 return std::make_unique<MenuGame<DdType, ValueType>>(
306 abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(),
307 transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(),
308 std::set<storm::expressions::Variable>(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()),
309 player2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap());
310}
311
312template<storm::dd::DdType DdType, typename ValueType>
313void JaniMenuGameAbstractor<DdType, ValueType>::exportToDot(std::string const& filename, storm::dd::Bdd<DdType> const& highlightStates,
314 storm::dd::Bdd<DdType> const& filter) const {
315 this->exportToDot(*currentGame, filename, highlightStates, filter);
316}
317
318template<storm::dd::DdType DdType, typename ValueType>
320 return abstractionInformation.getNumberOfPredicates();
321}
322
323template<storm::dd::DdType DdType, typename ValueType>
325 terminalStateExpressions.emplace_back(expression);
326}
327
328template<storm::dd::DdType DdType, typename ValueType>
330 for (auto& automaton : automata) {
331 automaton.notifyGuardsArePredicates();
332 }
333}
334
335// Explicitly instantiate the class.
338#ifdef STORM_HAVE_CARL
340#endif
341} // namespace jani
342} // namespace abstraction
343} // namespace storm::gbar
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
Definition Bdd.cpp:178
bool isZero() const
Retrieves whether this DD represents the constant zero function.
Definition Bdd.cpp:547
Bdd< LibraryType > andExists(Bdd< LibraryType > const &other, std::set< storm::expressions::Variable > const &existentialVariables) const
Computes the logical and of the current and the given BDD and existentially abstracts from the given ...
Definition Bdd.cpp:196
Bdd< LibraryType > swapVariables(std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &metaVariablePairs) const
Swaps the given pairs of meta variables in the BDD.
Definition Bdd.cpp:302
void addMetaVariables(std::set< storm::expressions::Variable > const &metaVariables)
Adds the given set of meta variables to the DD.
Definition Dd.cpp:44
DdManager< LibraryType > & getDdManager() const
Retrieves the manager that is responsible for this DD.
Definition Dd.cpp:39
storm::dd::Bdd< DdType > translate(storm::expressions::Expression const &expression)
This class represents a discrete-time stochastic two-player game.
Definition MenuGame.h:16
std::vector< storm::expressions::Expression > const & getPredicates() const
storm::expressions::Expression getInitialExpression() const override
Retrieves the expression that characterizes the initial states.
virtual void refine(RefinementCommand const &command) override
Performs the given refinement command.
storm::dd::DdManager< DdType > const & getDdManager() const override
MenuGame< DdType, ValueType > abstract() override
Uses the current set of predicates to derive the abstract menu game in the form of an ADD.
AbstractionInformation< DdType > const & getAbstractionInformation() const override
Retrieves information about the abstraction.
storm::expressions::Expression const & getGuard(uint64_t player1Choice) const override
Retrieves the guard predicate of the given player 1 choice.
JaniMenuGameAbstractor(storm::jani::Model const &model, std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory, MenuGameAbstractorOptions const &options=MenuGameAbstractorOptions())
Constructs an abstractor for the given model.
virtual uint64_t getNumberOfPredicates() const override
Retrieves the number of predicates currently in use.
std::map< storm::expressions::Variable, storm::expressions::Expression > getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const override
Retrieves a mapping from variables to expressions that define their updates wrt.
virtual std::set< storm::expressions::Variable > const & getAssignedVariables(uint64_t player1Choice) const override
Retrieves the variables assigned by the given player 1 choice.
virtual void exportToDot(std::string const &filename, storm::dd::Bdd< DdType > const &highlightStates, storm::dd::Bdd< DdType > const &filter) const override
Exports the current state of the abstraction in the dot format to the given file.
virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const override
Retrieves the number of updates of the specified player 1 choice.
std::pair< uint64_t, uint64_t > getPlayer1ChoiceRange() const override
Retrieves the range of player 1 choices.
virtual void notifyGuardsArePredicates() override
Notifies the abstractor that the guards are predicates, which may be used to improve the bottom state...
storm::dd::Bdd< DdType > getStates(storm::expressions::Expression const &expression) override
Retrieves a BDD that characterizes the states corresponding to the given expression.
virtual void addTerminalStates(storm::expressions::Expression const &expression) override
Adds the expression to the ones characterizing terminal states, i.e.
storm::expressions::Expression getInitialStatesExpression() const
Retrieves the expression defining the legal initial values of the variables.
Definition Model.cpp:1312
This class represents the settings for the abstraction procedures.
A class that provides convenience operations to display run times.
Definition Stopwatch.h:14
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SettingsType const & getModule()
Get module.
storm::dd::Bdd< Type > computeBackwardsReachableStates(storm::dd::Bdd< Type > const &initialStates, storm::dd::Bdd< Type > const &constraintStates, storm::dd::Bdd< Type > const &transitions, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables)
Definition dd.cpp:53
std::pair< storm::dd::Bdd< Type >, uint64_t > computeReachableStates(storm::dd::Bdd< Type > const &initialStates, storm::dd::Bdd< Type > const &transitions, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables)
Definition dd.cpp:16