2#include <boost/algorithm/string/join.hpp>
14template<
typename ValueType>
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;
25template<
typename ValueType>
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;
36template<
typename ValueType>
38 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
39 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
41 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
43 if (schedulerChoice.isDefined()) {
45 ++numOfUndefinedChoices;
49 assert(numOfUndefinedChoices > 0);
50 --numOfUndefinedChoices;
53 if (schedulerChoice.isDeterministic()) {
55 assert(numOfDeterministicChoices > 0);
56 --numOfDeterministicChoices;
60 ++numOfDeterministicChoices;
64 schedulerChoice = choice;
67template<
typename ValueType>
69 for (
auto selectedState : selectedStates) {
70 auto& schedulerChoice = schedulerChoices[memoryState][selectedState];
71 if (!schedulerChoice.isDefined()) {
78template<
typename ValueType>
80 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
81 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
85template<
typename ValueType>
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];
92template<
typename ValueType>
94 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
95 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
97 if (!dontCareStates[memoryState].get(modelState)) {
98 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
99 if (!schedulerChoice.isDefined() && setArbitraryChoice) {
101 this->setChoice(0, modelState, memoryState);
103 dontCareStates[memoryState].set(modelState,
true);
104 ++numOfDontCareStates;
108template<
typename ValueType>
110 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
111 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
113 if (dontCareStates[memoryState].get(modelState)) {
114 dontCareStates[memoryState].set(modelState,
false);
115 --numOfDontCareStates;
119template<
typename ValueType>
121 return dontCareStates[memoryState].get(modelState);
124template<
typename ValueType>
126 auto nrActions = nondeterministicChoiceIndices.back();
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]
137 result.
set(nondeterministicChoiceIndices[stateId] + schedChoice.first);
144template<
typename ValueType>
146 return numOfUndefinedChoices != 0;
149template<
typename ValueType>
151 return numOfDeterministicChoices == (schedulerChoices.size() * schedulerChoices.begin()->size()) - numOfUndefinedChoices;
154template<
typename ValueType>
156 return getNumberOfMemoryStates() == 1;
159template<
typename ValueType>
161 return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
164template<
typename ValueType>
166 return schedulerChoices.
empty() ? 0 : schedulerChoices.front().size();
169template<
typename ValueType>
171 return memoryStructure;
174template<
typename ValueType>
176 bool skipDontCareStates)
const {
177 STORM_LOG_THROW(model ==
nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
178 "The given model is not compatible with this scheduler.");
180 bool const stateValuationsGiven = model !=
nullptr && model->hasStateValuations();
181 bool const choiceLabelsGiven = model !=
nullptr && model->hasChoiceLabeling();
182 bool const choiceOriginsGiven = model !=
nullptr && model->hasChoiceOrigins();
183 uint_fast64_t widthOfStates = std::to_string(schedulerChoices.front().size()).length();
184 if (stateValuationsGiven) {
185 widthOfStates += model->getStateValuations().getStateInfo(schedulerChoices.front().size() - 1).length() + 5;
187 widthOfStates = std::max(widthOfStates, (uint_fast64_t)12);
188 uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
190 out <<
"___________________________________________________________________\n";
191 out << (isPartialScheduler() ?
"Partially" :
"Fully") <<
" defined ";
192 out << (isMemorylessScheduler() ?
"memoryless " :
"");
193 out << (isDeterministicScheduler() ?
"deterministic" :
"randomized") <<
" scheduler";
194 if (!isMemorylessScheduler()) {
195 out <<
" with " << getNumberOfMemoryStates() <<
" memory states";
198 STORM_LOG_WARN_COND(!(skipUniqueChoices && model ==
nullptr),
"Can not skip unique choices if the model is not given.");
199 out << std::setw(widthOfStates) <<
"model state:" <<
" " << (isMemorylessScheduler() ?
"" :
" memory: ") <<
"choice(s)"
200 << (isMemorylessScheduler() ?
"" :
" memory updates: ") <<
'\n';
201 for (uint_fast64_t state = 0; state < schedulerChoices.front().size(); ++state) {
203 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
204 ++numOfSkippedStatesWithUniqueChoice;
209 if (stateValuationsGiven) {
210 out << std::setw(widthOfStates) << (std::to_string(state) +
": " + model->getStateValuations().getStateInfo(state));
212 out << std::setw(widthOfStates) << state;
216 bool firstMemoryState =
true;
217 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
219 if (skipDontCareStates && isDontCare(state, memoryState)) {
224 if (firstMemoryState) {
225 firstMemoryState =
false;
227 out << std::setw(widthOfStates) <<
"";
231 if (!isMemorylessScheduler()) {
232 out <<
"m=" << memoryState << std::setw(8) <<
"";
239 if (choiceOriginsGiven) {
240 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] +
245 if (choiceLabelsGiven) {
246 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
248 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
251 bool firstChoice =
true;
258 out << choiceProbPair.second <<
": (";
259 if (choiceOriginsGiven) {
260 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
262 out << choiceProbPair.first;
264 if (choiceLabelsGiven) {
265 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
267 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
277 if (!isMemorylessScheduler()) {
278 STORM_LOG_THROW(model !=
nullptr, storm::exceptions::InvalidOperationException,
279 "Schedulers with memory can only be printed when the model is passed.");
280 out << std::setw(widthOfStates) <<
"";
284 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
285 bool firstUpdate =
true;
286 for (
auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end(); ++entryIt) {
292 out <<
"model state' = " << entryIt->getColumn() <<
": -> "
293 <<
"(m' = " << this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) <<
")";
303 if (numOfSkippedStatesWithUniqueChoice > 0) {
304 out <<
"Skipped " << numOfSkippedStatesWithUniqueChoice <<
" deterministic states with unique choice.\n";
306 out <<
"___________________________________________________________________\n";
309template<
typename ValueType>
311 bool skipDontCareStates)
const {
312 STORM_LOG_THROW(model ==
nullptr || model->getNumberOfStates() == schedulerChoices.front().size(), storm::exceptions::InvalidOperationException,
313 "The given model is not compatible with this scheduler.");
314 STORM_LOG_WARN_COND(!(skipUniqueChoices && model ==
nullptr),
"Can not skip unique choices if the model is not given.");
316 for (uint64_t state = 0; state < schedulerChoices.front().size(); ++state) {
318 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
322 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
324 if (skipDontCareStates && isDontCare(state, memoryState)) {
329 if (model && model->hasStateValuations()) {
330 stateChoicesJson[
"s"] = model->getStateValuations().template toJson<storm::RationalNumber>(state);
332 stateChoicesJson[
"s"] = state;
335 if (!isMemorylessScheduler()) {
336 stateChoicesJson[
"m"] = memoryState;
339 auto const& choice = schedulerChoices[memoryState][state];
341 if (choice.isDefined()) {
342 for (
auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
343 uint64_t globalChoiceIndex = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
345 if (model && model->hasChoiceOrigins() &&
346 model->getChoiceOrigins()->getIdentifier(globalChoiceIndex) != model->getChoiceOrigins()->getIdentifierForChoicesWithNoOrigin()) {
347 choiceJson[
"origin"] = model->getChoiceOrigins()->getChoiceAsJson(globalChoiceIndex);
349 if (model && model->hasChoiceLabeling()) {
350 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(globalChoiceIndex);
351 choiceJson[
"labels"] = std::vector<std::string>(choiceLabels.begin(), choiceLabels.end());
353 choiceJson[
"index"] = globalChoiceIndex;
354 choiceJson[
"prob"] = storm::utility::convertNumber<storm::RationalNumber>(choiceProbPair.second);
357 if (!isMemorylessScheduler()) {
358 STORM_LOG_THROW(model !=
nullptr, storm::exceptions::InvalidOperationException,
359 "Schedulers with memory can only be printed when the model is passed.");
360 choiceJson[
"memory-updates"] = std::vector<storm::json<storm::RationalNumber>>();
361 uint64_t row = model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first;
362 for (
auto entryIt = model->getTransitionMatrix().getRow(row).begin(); entryIt < model->getTransitionMatrix().getRow(row).end();
366 if (model && model->hasStateValuations()) {
367 updateJson[
"s'"] = model->getStateValuations().template toJson<storm::RationalNumber>(entryIt->getColumn());
369 updateJson[
"s'"] = entryIt->getColumn();
372 updateJson[
"m'"] = this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin());
373 choiceJson[
"memory-updates"].push_back(std::move(updateJson));
377 choicesJson.push_back(std::move(choiceJson));
380 choicesJson =
"undefined";
382 stateChoicesJson[
"c"] = std::move(choicesJson);
383 output.push_back(std::move(stateChoicesJson));
Base class for all sparse models.
A bit vector that is internally represented as a vector of 64-bit values.
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.
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.
void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0)
Clears the choice defined by the scheduler for the given state.
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.
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.
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?
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)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
nlohmann::basic_json< std::map, std::vector, std::string, bool, int64_t, uint64_t, ValueType > json
std::string dumpJson(storm::json< ValueType > const &j, bool compact)
Dumps the given json object, producing a String.