3#include <boost/algorithm/string/join.hpp>
15template<
typename ValueType>
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;
26template<
typename ValueType>
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;
37template<
typename ValueType>
39 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
40 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
42 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
44 if (schedulerChoice.isDefined()) {
46 ++numOfUndefinedChoices;
50 assert(numOfUndefinedChoices > 0);
51 --numOfUndefinedChoices;
54 if (schedulerChoice.isDeterministic()) {
56 assert(numOfDeterministicChoices > 0);
57 --numOfDeterministicChoices;
61 ++numOfDeterministicChoices;
65 schedulerChoice = choice;
68template<
typename ValueType>
70 for (
auto selectedState : selectedStates) {
71 auto& schedulerChoice = schedulerChoices[memoryState][selectedState];
72 if (!schedulerChoice.isDefined()) {
79template<
typename ValueType>
81 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
82 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
86template<
typename ValueType>
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];
93template<
typename ValueType>
95 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
96 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
98 if (!dontCareStates[memoryState].get(modelState)) {
99 auto& schedulerChoice = schedulerChoices[memoryState][modelState];
100 if (!schedulerChoice.isDefined() && setArbitraryChoice) {
102 this->setChoice(0, modelState, memoryState);
104 dontCareStates[memoryState].set(modelState,
true);
105 ++numOfDontCareStates;
109template<
typename ValueType>
111 STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(),
"Illegal memory state index");
112 STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(),
"Illegal model state index");
114 if (dontCareStates[memoryState].get(modelState)) {
115 dontCareStates[memoryState].set(modelState,
false);
116 --numOfDontCareStates;
120template<
typename ValueType>
122 return dontCareStates[memoryState].get(modelState);
125template<
typename ValueType>
127 auto nrActions = nondeterministicChoiceIndices.back();
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]
138 result.
set(nondeterministicChoiceIndices[stateId] + schedChoice.first);
145template<
typename ValueType>
147 return numOfUndefinedChoices != 0;
150template<
typename ValueType>
152 return numOfDeterministicChoices == (schedulerChoices.size() * schedulerChoices.begin()->size()) - numOfUndefinedChoices;
155template<
typename ValueType>
157 return getNumberOfMemoryStates() == 1;
160template<
typename ValueType>
162 return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
165template<
typename ValueType>
167 return schedulerChoices.
empty() ? 0 : schedulerChoices.front().size();
170template<
typename ValueType>
172 return memoryStructure;
175template<
typename ValueType>
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.");
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;
188 widthOfStates = std::max(widthOfStates, (uint_fast64_t)12);
189 uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
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";
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) {
204 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
205 ++numOfSkippedStatesWithUniqueChoice;
210 if (stateValuationsGiven) {
211 out << std::setw(widthOfStates) << (std::to_string(state) +
": " + model->getStateValuations().getStateInfo(state));
213 out << std::setw(widthOfStates) << state;
217 bool firstMemoryState =
true;
218 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
220 if (skipDontCareStates && isDontCare(state, memoryState)) {
225 if (firstMemoryState) {
226 firstMemoryState =
false;
228 out << std::setw(widthOfStates) <<
"";
232 if (!isMemorylessScheduler()) {
233 out <<
"m=" << memoryState << std::setw(8) <<
"";
240 if (choiceOriginsGiven) {
241 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] +
246 if (choiceLabelsGiven) {
247 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
249 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
252 bool firstChoice =
true;
259 out << choiceProbPair.second <<
": (";
260 if (choiceOriginsGiven) {
261 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
263 out << choiceProbPair.first;
265 if (choiceLabelsGiven) {
266 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
268 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
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) <<
"";
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) {
293 out <<
"model state' = " << entryIt->getColumn() <<
": -> "
294 <<
"(m' = " << this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) <<
")";
304 if (numOfSkippedStatesWithUniqueChoice > 0) {
305 out <<
"Skipped " << numOfSkippedStatesWithUniqueChoice <<
" deterministic states with unique choice.\n";
307 out <<
"___________________________________________________________________\n";
310template<
typename ValueType>
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) {
319 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
323 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
325 if (skipDontCareStates && isDontCare(state, memoryState)) {
330 if (model && model->hasStateValuations()) {
331 stateChoicesJson[
"s"] = model->getStateValuations().template toJson<storm::RationalNumber>(state);
333 stateChoicesJson[
"s"] = state;
336 if (!isMemorylessScheduler()) {
337 stateChoicesJson[
"m"] = memoryState;
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);
350 if (model && model->hasChoiceLabeling()) {
351 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(globalChoiceIndex);
352 choiceJson[
"labels"] = std::vector<std::string>(choiceLabels.begin(), choiceLabels.end());
354 choiceJson[
"index"] = globalChoiceIndex;
355 choiceJson[
"prob"] = storm::utility::convertNumber<storm::RationalNumber>(choiceProbPair.second);
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();
367 if (model && model->hasStateValuations()) {
368 updateJson[
"s'"] = model->getStateValuations().template toJson<storm::RationalNumber>(entryIt->getColumn());
370 updateJson[
"s'"] = entryIt->getColumn();
373 updateJson[
"m'"] = this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin());
374 choiceJson[
"memory-updates"].push_back(std::move(updateJson));
378 choicesJson.push_back(std::move(choiceJson));
381 choicesJson =
"undefined";
383 stateChoicesJson[
"c"] = std::move(choicesJson);
384 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.