Storm 1.11.1.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>
80void Scheduler<ValueType>::clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState) {
81 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
82 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
83 setChoice(SchedulerChoice<ValueType>(), modelState, memoryState);
84}
85
86template<typename ValueType>
87SchedulerChoice<ValueType> const& Scheduler<ValueType>::getChoice(uint_fast64_t modelState, uint_fast64_t memoryState) const {
88 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
89 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
90 return schedulerChoices[memoryState][modelState];
91}
92
93template<typename ValueType>
94void Scheduler<ValueType>::setDontCare(uint_fast64_t modelState, uint_fast64_t memoryState, bool setArbitraryChoice) {
95 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
96 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
97
98 if (!dontCareStates[memoryState].get(modelState)) {
99 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
100 if (!schedulerChoice.isDefined() && setArbitraryChoice) {
101 // Set an arbitrary choice
102 this->setChoice(0, modelState, memoryState);
103 }
104 dontCareStates[memoryState].set(modelState, true);
105 ++numOfDontCareStates;
106 }
107}
108
109template<typename ValueType>
110void Scheduler<ValueType>::unSetDontCare(uint_fast64_t modelState, uint_fast64_t memoryState) {
111 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
112 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
113
114 if (dontCareStates[memoryState].get(modelState)) {
115 dontCareStates[memoryState].set(modelState, false);
116 --numOfDontCareStates;
117 }
118}
119
120template<typename ValueType>
121bool Scheduler<ValueType>::isDontCare(uint_fast64_t modelState, uint64_t memoryState) const {
122 return dontCareStates[memoryState].get(modelState);
123}
124
125template<typename ValueType>
126storm::storage::BitVector Scheduler<ValueType>::computeActionSupport(std::vector<uint_fast64_t> const& nondeterministicChoiceIndices) const {
127 auto nrActions = nondeterministicChoiceIndices.back();
128 storm::storage::BitVector result(nrActions);
129
130 for (auto const& choicesPerMemoryNode : schedulerChoices) {
131 STORM_LOG_ASSERT(nondeterministicChoiceIndices.size() - 2 < choicesPerMemoryNode.size(), "Illegal model state index");
132 for (uint64_t stateId = 0; stateId < nondeterministicChoiceIndices.size() - 1; ++stateId) {
133 for (auto const& schedChoice : choicesPerMemoryNode[stateId].getChoiceAsDistribution()) {
134 STORM_LOG_ASSERT(schedChoice.first < nondeterministicChoiceIndices[stateId + 1] - nondeterministicChoiceIndices[stateId],
135 "Scheduler chooses action indexed " << schedChoice.first << " in state id " << stateId << " but state contains only "
136 << nondeterministicChoiceIndices[stateId + 1] - nondeterministicChoiceIndices[stateId]
137 << " choices .");
138 result.set(nondeterministicChoiceIndices[stateId] + schedChoice.first);
139 }
140 }
141 }
142 return result;
143}
144
145template<typename ValueType>
147 return numOfUndefinedChoices != 0;
148}
149
150template<typename ValueType>
152 return numOfDeterministicChoices == (schedulerChoices.size() * schedulerChoices.begin()->size()) - numOfUndefinedChoices;
153}
154
155template<typename ValueType>
157 return getNumberOfMemoryStates() == 1;
158}
159
160template<typename ValueType>
162 return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
163}
164
165template<typename ValueType>
167 return schedulerChoices.empty() ? 0 : schedulerChoices.front().size();
168}
169
170template<typename ValueType>
171boost::optional<storm::storage::MemoryStructure> const& Scheduler<ValueType>::getMemoryStructure() const {
172 return memoryStructure;
173}
174
175template<typename ValueType>
176void Scheduler<ValueType>::printToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, bool skipUniqueChoices,
177 bool skipDontCareStates) const {
178 STORM_LOG_THROW(model == nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
179 "The given model is not compatible with this scheduler.");
180
181 bool const stateValuationsGiven = model != nullptr && model->hasStateValuations();
182 bool const choiceLabelsGiven = model != nullptr && model->hasChoiceLabeling();
183 bool const choiceOriginsGiven = model != nullptr && model->hasChoiceOrigins();
184 uint_fast64_t widthOfStates = std::to_string(schedulerChoices.front().size()).length();
185 if (stateValuationsGiven) {
186 widthOfStates += model->getStateValuations().getStateInfo(schedulerChoices.front().size() - 1).length() + 5;
187 }
188 widthOfStates = std::max(widthOfStates, (uint_fast64_t)12);
189 uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
190
191 out << "___________________________________________________________________\n";
192 out << (isPartialScheduler() ? "Partially" : "Fully") << " defined ";
193 out << (isMemorylessScheduler() ? "memoryless " : "");
194 out << (isDeterministicScheduler() ? "deterministic" : "randomized") << " scheduler";
195 if (!isMemorylessScheduler()) {
196 out << " with " << getNumberOfMemoryStates() << " memory states";
197 }
198 out << ":\n";
199 STORM_LOG_WARN_COND(!(skipUniqueChoices && model == nullptr), "Can not skip unique choices if the model is not given.");
200 out << std::setw(widthOfStates) << "model state:" << " " << (isMemorylessScheduler() ? "" : " memory: ") << "choice(s)"
201 << (isMemorylessScheduler() ? "" : " memory updates: ") << '\n';
202 for (uint_fast64_t state = 0; state < schedulerChoices.front().size(); ++state) {
203 // Check whether the state is skipped
204 if (skipUniqueChoices && model != nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
205 ++numOfSkippedStatesWithUniqueChoice;
206 continue;
207 }
208
209 // Print the state info
210 if (stateValuationsGiven) {
211 out << std::setw(widthOfStates) << (std::to_string(state) + ": " + model->getStateValuations().getStateInfo(state));
212 } else {
213 out << std::setw(widthOfStates) << state;
214 }
215 out << " ";
216
217 bool firstMemoryState = true;
218 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
219 // Ignore dontCare states
220 if (skipDontCareStates && isDontCare(state, memoryState)) {
221 continue;
222 }
223
224 // Indent if this is not the first memory state
225 if (firstMemoryState) {
226 firstMemoryState = false;
227 } else {
228 out << std::setw(widthOfStates) << "";
229 out << " ";
230 }
231 // Print the memory state info
232 if (!isMemorylessScheduler()) {
233 out << "m=" << memoryState << std::setw(8) << "";
234 }
235
236 // Print choice info
237 SchedulerChoice<ValueType> const& choice = schedulerChoices[memoryState][state];
238 if (choice.isDefined()) {
239 if (choice.isDeterministic()) {
240 if (choiceOriginsGiven) {
241 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] +
242 choice.getDeterministicChoice());
243 } else {
244 out << choice.getDeterministicChoice();
245 }
246 if (choiceLabelsGiven) {
247 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
248 choice.getDeterministicChoice());
249 out << " {" << boost::join(choiceLabels, ", ") << "}";
250 }
251 } else {
252 bool firstChoice = true;
253 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
254 if (firstChoice) {
255 firstChoice = false;
256 } else {
257 out << " + ";
258 }
259 out << choiceProbPair.second << ": (";
260 if (choiceOriginsGiven) {
261 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
262 } else {
263 out << choiceProbPair.first;
264 }
265 if (choiceLabelsGiven) {
266 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
267 choice.getDeterministicChoice());
268 out << " {" << boost::join(choiceLabels, ", ") << "}";
269 }
270 out << ")";
271 }
272 }
273 } else {
274 out << "undefined.";
275 }
276
277 // Print memory updates
278 if (!isMemorylessScheduler()) {
279 STORM_LOG_THROW(model != nullptr, storm::exceptions::InvalidOperationException,
280 "Schedulers with memory can only be printed when the model is passed.");
281 out << std::setw(widthOfStates) << "";
282 // 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
283 // state.
284 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
285 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
286 bool firstUpdate = true;
287 for (auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end(); ++entryIt) {
288 if (firstUpdate) {
289 firstUpdate = false;
290 } else {
291 out << ", ";
292 }
293 out << "model state' = " << entryIt->getColumn() << ": -> "
294 << "(m' = " << this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) << ")";
295 // out << "model state' = " << entryIt->getColumn() << ": (transition = " << entryIt - model->getTransitionMatrix().begin() << ") -> "
296 // << "(m' = "<<this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) <<")";
297 }
298 }
299 }
300
301 out << '\n';
302 }
303 }
304 if (numOfSkippedStatesWithUniqueChoice > 0) {
305 out << "Skipped " << numOfSkippedStatesWithUniqueChoice << " deterministic states with unique choice.\n";
306 }
307 out << "___________________________________________________________________\n";
308}
309
310template<typename ValueType>
311void Scheduler<ValueType>::printJsonToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, bool skipUniqueChoices,
312 bool skipDontCareStates) const {
313 STORM_LOG_THROW(model == nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
314 "The given model is not compatible with this scheduler.");
315 STORM_LOG_WARN_COND(!(skipUniqueChoices && model == nullptr), "Can not skip unique choices if the model is not given.");
317 for (uint64_t state = 0; state < schedulerChoices.front().size(); ++state) {
318 // Check whether the state is skipped
319 if (skipUniqueChoices && model != nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
320 continue;
321 }
322
323 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
324 // Ignore dontCare states
325 if (skipDontCareStates && isDontCare(state, memoryState)) {
326 continue;
327 }
328
329 storm::json<storm::RationalNumber> stateChoicesJson;
330 if (model && model->hasStateValuations()) {
331 stateChoicesJson["s"] = model->getStateValuations().template toJson<storm::RationalNumber>(state);
332 } else {
333 stateChoicesJson["s"] = state;
334 }
335
336 if (!isMemorylessScheduler()) {
337 stateChoicesJson["m"] = memoryState;
338 }
339
340 auto const& choice = schedulerChoices[memoryState][state];
342 if (choice.isDefined()) {
343 for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
344 uint64_t globalChoiceIndex = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
346 if (model && model->hasChoiceOrigins() &&
347 model->getChoiceOrigins()->getIdentifier(globalChoiceIndex) != model->getChoiceOrigins()->getIdentifierForChoicesWithNoOrigin()) {
348 choiceJson["origin"] = model->getChoiceOrigins()->getChoiceAsJson(globalChoiceIndex);
349 }
350 if (model && model->hasChoiceLabeling()) {
351 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(globalChoiceIndex);
352 choiceJson["labels"] = std::vector<std::string>(choiceLabels.begin(), choiceLabels.end());
353 }
354 choiceJson["index"] = globalChoiceIndex;
355 choiceJson["prob"] = storm::utility::convertNumber<storm::RationalNumber>(choiceProbPair.second);
356
357 // Memory updates
358 if (!isMemorylessScheduler()) {
359 STORM_LOG_THROW(model != nullptr, storm::exceptions::InvalidOperationException,
360 "Schedulers with memory can only be printed when the model is passed.");
361 choiceJson["memory-updates"] = std::vector<storm::json<storm::RationalNumber>>();
362 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
363 for (auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end();
364 ++entryIt) {
366 // next model state
367 if (model && model->hasStateValuations()) {
368 updateJson["s'"] = model->getStateValuations().template toJson<storm::RationalNumber>(entryIt->getColumn());
369 } else {
370 updateJson["s'"] = entryIt->getColumn();
371 }
372 // next memory state
373 updateJson["m'"] = this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin());
374 choiceJson["memory-updates"].push_back(std::move(updateJson));
375 }
376 }
377
378 choicesJson.push_back(std::move(choiceJson));
379 }
380 } else {
381 choicesJson = "undefined";
382 }
383 stateChoicesJson["c"] = std::move(choicesJson);
384 output.push_back(std::move(stateChoicesJson));
385 }
386 }
387 out << storm::dumpJson(output);
388}
389
390template class Scheduler<double>;
393template class Scheduler<storm::Interval>;
394
395} // namespace storage
396} // namespace storm
Base class for all sparse models.
Definition Model.h:32
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
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:87
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:80
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(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.
Definition Scheduler.cpp:94
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
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.