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