Storm 1.13.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Scheduler.cpp
Go to the documentation of this file.
2
3#include <boost/algorithm/string/join.hpp>
4
11
12namespace storm {
13namespace storage {
14
15template<typename ValueType>
16Scheduler<ValueType>::Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure)
17 : memoryStructure(memoryStructure) {
18 uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
19 schedulerChoices = std::vector<std::vector<SchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<SchedulerChoice<ValueType>>(numberOfModelStates));
20 dontCareStates = std::vector<storm::storage::BitVector>(numOfMemoryStates, storm::storage::BitVector(numberOfModelStates, false));
21 numOfUndefinedChoices = numOfMemoryStates * numberOfModelStates;
22 numOfDeterministicChoices = 0;
23 numOfDontCareStates = 0;
24}
25
26template<typename ValueType>
27Scheduler<ValueType>::Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure)
28 : memoryStructure(std::move(memoryStructure)) {
29 uint_fast64_t numOfMemoryStates = this->memoryStructure ? this->memoryStructure->getNumberOfStates() : 1;
30 schedulerChoices = std::vector<std::vector<SchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<SchedulerChoice<ValueType>>(numberOfModelStates));
31 dontCareStates = std::vector<storm::storage::BitVector>(numOfMemoryStates, storm::storage::BitVector(numberOfModelStates, false));
32 numOfUndefinedChoices = numOfMemoryStates * numberOfModelStates;
33 numOfDeterministicChoices = 0;
34 numOfDontCareStates = 0;
35}
36
37template<typename ValueType>
38void Scheduler<ValueType>::setChoice(SchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState) {
39 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
40 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
41
42 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
43
44 if (schedulerChoice.isDefined()) {
45 if (!choice.isDefined()) {
46 ++numOfUndefinedChoices;
47 }
48 } else {
49 if (choice.isDefined()) {
50 assert(numOfUndefinedChoices > 0);
51 --numOfUndefinedChoices;
52 }
53 }
54 if (schedulerChoice.isDeterministic()) {
55 if (!choice.isDeterministic()) {
56 assert(numOfDeterministicChoices > 0);
57 --numOfDeterministicChoices;
58 }
59 } else {
60 if (choice.isDeterministic()) {
61 ++numOfDeterministicChoices;
62 }
63 }
64
65 schedulerChoice = choice;
66}
67
68template<typename ValueType>
69bool Scheduler<ValueType>::isChoiceSelected(BitVector const& selectedStates, uint64_t memoryState) const {
70 for (auto selectedState : selectedStates) {
71 auto& schedulerChoice = schedulerChoices[memoryState][selectedState];
72 if (!schedulerChoice.isDefined()) {
73 return false;
74 }
75 }
76 return true;
77}
78
79template<typename ValueType>
80bool Scheduler<ValueType>::isChoiceSelected(uint64_t modelState, uint64_t memoryState) const {
81 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
82 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
83 return schedulerChoices[memoryState][modelState].isDefined();
84}
85
86template<typename ValueType>
87void Scheduler<ValueType>::clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState) {
88 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
89 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
90 setChoice(SchedulerChoice<ValueType>(), modelState, memoryState);
91}
92
93template<typename ValueType>
94SchedulerChoice<ValueType> const& Scheduler<ValueType>::getChoice(uint_fast64_t modelState, uint_fast64_t memoryState) const {
95 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
96 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
97 return schedulerChoices[memoryState][modelState];
98}
99
100template<typename ValueType>
101void Scheduler<ValueType>::setDontCare(uint_fast64_t modelState, uint_fast64_t memoryState, bool setArbitraryChoice) {
102 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
103 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
104
105 if (!dontCareStates[memoryState].get(modelState)) {
106 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
107 if (!schedulerChoice.isDefined() && setArbitraryChoice) {
108 // Set an arbitrary choice
109 this->setChoice(0, modelState, memoryState);
110 }
111 dontCareStates[memoryState].set(modelState, true);
112 ++numOfDontCareStates;
113 }
114}
115
116template<typename ValueType>
117void Scheduler<ValueType>::unSetDontCare(uint_fast64_t modelState, uint_fast64_t memoryState) {
118 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
119 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
120
121 if (dontCareStates[memoryState].get(modelState)) {
122 dontCareStates[memoryState].set(modelState, false);
123 --numOfDontCareStates;
124 }
125}
126
127template<typename ValueType>
128bool Scheduler<ValueType>::isDontCare(uint_fast64_t modelState, uint64_t memoryState) const {
129 return dontCareStates[memoryState].get(modelState);
130}
131
132template<typename ValueType>
133storm::storage::BitVector Scheduler<ValueType>::computeActionSupport(std::vector<uint_fast64_t> const& nondeterministicChoiceIndices) const {
134 auto nrActions = nondeterministicChoiceIndices.back();
135 storm::storage::BitVector result(nrActions);
136
137 for (auto const& choicesPerMemoryNode : schedulerChoices) {
138 STORM_LOG_ASSERT(nondeterministicChoiceIndices.size() - 2 < choicesPerMemoryNode.size(), "Illegal model state index");
139 for (uint64_t stateId = 0; stateId < nondeterministicChoiceIndices.size() - 1; ++stateId) {
140 for (auto const& schedChoice : choicesPerMemoryNode[stateId].getChoiceAsDistribution()) {
141 STORM_LOG_ASSERT(schedChoice.first < nondeterministicChoiceIndices[stateId + 1] - nondeterministicChoiceIndices[stateId],
142 "Scheduler chooses action indexed " << schedChoice.first << " in state id " << stateId << " but state contains only "
143 << nondeterministicChoiceIndices[stateId + 1] - nondeterministicChoiceIndices[stateId]
144 << " choices .");
145 result.set(nondeterministicChoiceIndices[stateId] + schedChoice.first);
146 }
147 }
148 }
149 return result;
150}
151
152template<typename ValueType>
154 return numOfUndefinedChoices != 0;
155}
156
157template<typename ValueType>
159 return numOfDeterministicChoices == (schedulerChoices.size() * schedulerChoices.begin()->size()) - numOfUndefinedChoices;
160}
161
162template<typename ValueType>
166
167template<typename ValueType>
169 return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
170}
171
172template<typename ValueType>
174 return schedulerChoices.empty() ? 0 : schedulerChoices.front().size();
175}
176
177template<typename ValueType>
178boost::optional<storm::storage::MemoryStructure> const& Scheduler<ValueType>::getMemoryStructure() const {
179 return memoryStructure;
180}
181
182template<typename ValueType>
184 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
185
186 Scheduler<ValueType> memorylessScheduler(getNumberOfModelStates());
187 for (uint64_t modelState = 0; modelState < getNumberOfModelStates(); ++modelState) {
188 if (schedulerChoices[memoryState][modelState].isDefined()) {
189 memorylessScheduler.setChoice(schedulerChoices[memoryState][modelState], modelState);
190 }
191 }
192 return memorylessScheduler;
193}
194
195template<typename ValueType>
196void Scheduler<ValueType>::printToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, bool skipUniqueChoices,
197 bool skipDontCareStates) const {
198 STORM_LOG_THROW(model == nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
199 "The given model is not compatible with this scheduler.");
200
201 bool const stateValuationsGiven = model != nullptr && model->hasStateValuations();
202 bool const choiceLabelsGiven = model != nullptr && model->hasChoiceLabeling();
203 bool const choiceOriginsGiven = model != nullptr && model->hasChoiceOrigins();
204 uint_fast64_t widthOfStates = std::to_string(schedulerChoices.front().size()).length();
205 if (stateValuationsGiven) {
206 widthOfStates += model->getStateValuations().getStateInfo(schedulerChoices.front().size() - 1).length() + 5;
207 }
208 widthOfStates = std::max(widthOfStates, (uint_fast64_t)12);
209 uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
210
211 out << "___________________________________________________________________\n";
212 out << (isPartialScheduler() ? "Partially" : "Fully") << " defined ";
213 out << (isMemorylessScheduler() ? "memoryless " : "");
214 out << (isDeterministicScheduler() ? "deterministic" : "randomized") << " scheduler";
215 if (!isMemorylessScheduler()) {
216 out << " with " << getNumberOfMemoryStates() << " memory states";
217 }
218 out << ":\n";
219 STORM_LOG_WARN_COND(!(skipUniqueChoices && model == nullptr), "Can not skip unique choices if the model is not given.");
220 out << std::setw(widthOfStates) << "model state:" << " " << (isMemorylessScheduler() ? "" : " memory: ") << "choice(s)"
221 << (isMemorylessScheduler() ? "" : " memory updates: ") << '\n';
222 for (uint_fast64_t state = 0; state < schedulerChoices.front().size(); ++state) {
223 // Check whether the state is skipped
224 if (skipUniqueChoices && model != nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
225 ++numOfSkippedStatesWithUniqueChoice;
226 continue;
227 }
228
229 // Print the state info
230 if (stateValuationsGiven) {
231 out << std::setw(widthOfStates) << (std::to_string(state) + ": " + model->getStateValuations().getStateInfo(state));
232 } else {
233 out << std::setw(widthOfStates) << state;
234 }
235 out << " ";
236
237 bool firstMemoryState = true;
238 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
239 // Ignore dontCare states
240 if (skipDontCareStates && isDontCare(state, memoryState)) {
241 continue;
242 }
243
244 // Indent if this is not the first memory state
245 if (firstMemoryState) {
246 firstMemoryState = false;
247 } else {
248 out << std::setw(widthOfStates) << "";
249 out << " ";
250 }
251 // Print the memory state info
252 if (!isMemorylessScheduler()) {
253 out << "m=" << memoryState << std::setw(8) << "";
254 }
255
256 // Print choice info
257 SchedulerChoice<ValueType> const& choice = schedulerChoices[memoryState][state];
258 if (choice.isDefined()) {
259 if (choice.isDeterministic()) {
260 if (choiceOriginsGiven) {
261 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] +
262 choice.getDeterministicChoice());
263 } else {
264 out << choice.getDeterministicChoice();
265 }
266 if (choiceLabelsGiven) {
267 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
268 choice.getDeterministicChoice());
269 out << " {" << boost::join(choiceLabels, ", ") << "}";
270 }
271 } else {
272 bool firstChoice = true;
273 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
274 if (firstChoice) {
275 firstChoice = false;
276 } else {
277 out << " + ";
278 }
279 out << choiceProbPair.second << ": (";
280 if (choiceOriginsGiven) {
281 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
282 } else {
283 out << choiceProbPair.first;
284 }
285 if (choiceLabelsGiven) {
286 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
287 choice.getDeterministicChoice());
288 out << " {" << boost::join(choiceLabels, ", ") << "}";
289 }
290 out << ")";
291 }
292 }
293 } else {
294 out << "undefined.";
295 }
296
297 // Print memory updates
298 if (!isMemorylessScheduler()) {
299 STORM_LOG_THROW(model != nullptr, storm::exceptions::InvalidOperationException,
300 "Schedulers with memory can only be printed when the model is passed.");
301 out << std::setw(widthOfStates) << "";
302 // The memory updates do not depend on the actual choice, they only depend on the current model- and memory state as well as the successor model
303 // state.
304 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
305 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
306 bool firstUpdate = true;
307 for (auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end(); ++entryIt) {
308 if (firstUpdate) {
309 firstUpdate = false;
310 } else {
311 out << ", ";
312 }
313 out << "model state' = " << entryIt->getColumn() << ": -> "
314 << "(m' = " << this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) << ")";
315 // out << "model state' = " << entryIt->getColumn() << ": (transition = " << entryIt - model->getTransitionMatrix().begin() << ") -> "
316 // << "(m' = "<<this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) <<")";
317 }
318 }
319 }
320
321 out << '\n';
322 }
323 }
324 if (numOfSkippedStatesWithUniqueChoice > 0) {
325 out << "Skipped " << numOfSkippedStatesWithUniqueChoice << " deterministic states with unique choice.\n";
326 }
327 out << "___________________________________________________________________\n";
328}
329
330template<typename ValueType>
331void Scheduler<ValueType>::printJsonToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, bool skipUniqueChoices,
332 bool skipDontCareStates) const {
333 STORM_LOG_THROW(model == nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
334 "The given model is not compatible with this scheduler.");
335 STORM_LOG_WARN_COND(!(skipUniqueChoices && model == nullptr), "Can not skip unique choices if the model is not given.");
337 for (uint64_t state = 0; state < schedulerChoices.front().size(); ++state) {
338 // Check whether the state is skipped
339 if (skipUniqueChoices && model != nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
340 continue;
341 }
342
343 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
344 // Ignore dontCare states
345 if (skipDontCareStates && isDontCare(state, memoryState)) {
346 continue;
347 }
348
349 storm::json<storm::RationalNumber> stateChoicesJson;
350 if (model && model->hasStateValuations()) {
351 stateChoicesJson["s"] = model->getStateValuations().template toJson<storm::RationalNumber>(state);
352 } else {
353 stateChoicesJson["s"] = state;
354 }
355
356 if (!isMemorylessScheduler()) {
357 stateChoicesJson["m"] = memoryState;
358 }
359
360 auto const& choice = schedulerChoices[memoryState][state];
362 if (choice.isDefined()) {
363 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
364 uint64_t globalChoiceIndex = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
366 if (model && model->hasChoiceOrigins() &&
367 model->getChoiceOrigins()->getIdentifier(globalChoiceIndex) != model->getChoiceOrigins()->getIdentifierForChoicesWithNoOrigin()) {
368 choiceJson["origin"] = model->getChoiceOrigins()->getChoiceAsJson(globalChoiceIndex);
369 }
370 if (model && model->hasChoiceLabeling()) {
371 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(globalChoiceIndex);
372 choiceJson["labels"] = std::vector<std::string>(choiceLabels.begin(), choiceLabels.end());
373 }
374 choiceJson["index"] = globalChoiceIndex;
375 choiceJson["prob"] = storm::utility::convertNumber<storm::RationalNumber>(choiceProbPair.second);
376
377 // Memory updates
378 if (!isMemorylessScheduler()) {
379 STORM_LOG_THROW(model != nullptr, storm::exceptions::InvalidOperationException,
380 "Schedulers with memory can only be printed when the model is passed.");
381 choiceJson["memory-updates"] = std::vector<storm::json<storm::RationalNumber>>();
382 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
383 for (auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end();
384 ++entryIt) {
386 // next model state
387 if (model && model->hasStateValuations()) {
388 updateJson["s'"] = model->getStateValuations().template toJson<storm::RationalNumber>(entryIt->getColumn());
389 } else {
390 updateJson["s'"] = entryIt->getColumn();
391 }
392 // next memory state
393 updateJson["m'"] = this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin());
394 choiceJson["memory-updates"].push_back(std::move(updateJson));
395 }
396 }
397
398 choicesJson.push_back(std::move(choiceJson));
399 }
400 } else {
401 choicesJson = "undefined";
402 }
403 stateChoicesJson["c"] = std::move(choicesJson);
404 output.push_back(std::move(stateChoicesJson));
405 }
406 }
407 out << storm::dumpJson(output);
408}
409
410template class Scheduler<double>;
413template class Scheduler<storm::Interval>;
415
416} // namespace storage
417} // namespace storm
Base class for all sparse models.
Definition Model.h:30
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
uint_fast64_t getDeterministicChoice() const
If this choice is deterministic, this function returns the selected (local) choice index.
storm::storage::Distribution< ValueType, uint_fast64_t > const & getChoiceAsDistribution() const
Retrieves this choice in the form of a probability distribution.
bool isDeterministic() const
Returns true iff this scheduler choice is deterministic (i.e., not randomized).
bool isDefined() const
Returns true iff this scheduler choice is defined.
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
bool isDeterministicScheduler() const
Retrieves whether all defined choices are deterministic.
storm::storage::BitVector computeActionSupport(std::vector< uint64_t > const &nondeterministicChoiceIndicies) const
Compute the Action Support: A bit vector that indicates all actions that are selected with positive p...
void unSetDontCare(uint_fast64_t modelState, uint_fast64_t memoryState=0)
Unset the combination of model state and memoryStructure state to dontCare.
bool isPartialScheduler() const
Retrieves whether there is a reachable pair of model and memory state for which the choice is undefin...
uint_fast64_t getNumberOfModelStates() const
Retrieves the number of model states this scheduler considers.
SchedulerChoice< ValueType > const & getChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0) const
Gets the choice defined by the scheduler for the given model and memory state.
Definition Scheduler.cpp:94
void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0)
Clears the choice defined by the scheduler for the given state.
Definition Scheduler.cpp:87
bool isDontCare(uint_fast64_t modelState, uint64_t memoryState=0) const
Is the combination of model state and memoryStructure state to reachable?
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
Definition Scheduler.cpp:38
void printJsonToStream(std::ostream &out, std::shared_ptr< storm::models::sparse::Model< ValueType > > model=nullptr, bool skipUniqueChoices=false, bool skipDontCareStates=false) const
Prints the scheduler in json format to the given output stream.
boost::optional< storm::storage::MemoryStructure > const & getMemoryStructure() const
Retrieves the memory structure associated with this scheduler.
uint_fast64_t getNumberOfMemoryStates() const
Retrieves the number of memory states this scheduler considers.
void printToStream(std::ostream &out, std::shared_ptr< storm::models::sparse::Model< ValueType > > model=nullptr, bool skipUniqueChoices=false, bool skipDontCareStates=false) const
Prints the scheduler to the given output stream.
Scheduler< ValueType > getMemorylessSchedulerForMemoryState(uint64_t memoryState=0) const
Retrieves a memoryless scheduler that corresponds to the given memory state.
Scheduler(uint_fast64_t numberOfModelStates, boost::optional< storm::storage::MemoryStructure > const &memoryStructure=boost::none)
Initializes a scheduler for the given number of model states.
Definition Scheduler.cpp:16
void setDontCare(uint_fast64_t modelState, uint_fast64_t memoryState=0, bool setArbitraryChoice=true)
Set the combination of model state and memoryStructure state to dontCare.
bool isChoiceSelected(BitVector const &selectedStates, uint64_t memoryState=0) const
Is the scheduler defined on the states indicated by the selected-states bitvector?
Definition Scheduler.cpp:69
bool isMemorylessScheduler() const
Retrieves whether the scheduler considers a trivial memory structure (i.e., a memory structure with j...
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
TargetType convertNumber(SourceType const &number)
nlohmann::basic_json< std::map, std::vector, std::string, bool, int64_t, uint64_t, ValueType > json
Definition JsonForward.h:10
std::string dumpJson(storm::json< ValueType > const &j, bool compact)
Dumps the given json object, producing a String.