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 memoryStructure;
169template<
typename ValueType>
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.");
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;
182 widthOfStates = std::max(widthOfStates, (uint_fast64_t)12);
183 uint_fast64_t numOfSkippedStatesWithUniqueChoice = 0;
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";
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) {
198 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
199 ++numOfSkippedStatesWithUniqueChoice;
204 if (stateValuationsGiven) {
205 out << std::setw(widthOfStates) << (std::to_string(state) +
": " + model->getStateValuations().getStateInfo(state));
207 out << std::setw(widthOfStates) << state;
211 bool firstMemoryState =
true;
212 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
214 if (skipDontCareStates && isDontCare(state, memoryState)) {
219 if (firstMemoryState) {
220 firstMemoryState =
false;
222 out << std::setw(widthOfStates) <<
"";
226 if (!isMemorylessScheduler()) {
227 out <<
"m=" << memoryState << std::setw(8) <<
"";
234 if (choiceOriginsGiven) {
235 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] +
240 if (choiceLabelsGiven) {
241 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
243 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
246 bool firstChoice =
true;
253 out << choiceProbPair.second <<
": (";
254 if (choiceOriginsGiven) {
255 out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
257 out << choiceProbPair.first;
259 if (choiceLabelsGiven) {
260 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(model->getTransitionMatrix().getRowGroupIndices()[state] +
262 out <<
" {" << boost::join(choiceLabels,
", ") <<
"}";
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) <<
"";
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) {
287 out <<
"model state' = " << entryIt->getColumn() <<
": -> "
288 <<
"(m' = " << this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin()) <<
")";
298 if (numOfSkippedStatesWithUniqueChoice > 0) {
299 out <<
"Skipped " << numOfSkippedStatesWithUniqueChoice <<
" deterministic states with unique choice.\n";
301 out <<
"___________________________________________________________________\n";
304template<
typename ValueType>
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) {
313 if (skipUniqueChoices && model !=
nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
317 for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
319 if (skipDontCareStates && isDontCare(state, memoryState)) {
324 if (model && model->hasStateValuations()) {
325 stateChoicesJson[
"s"] = model->getStateValuations().template toJson<storm::RationalNumber>(state);
327 stateChoicesJson[
"s"] = state;
330 if (!isMemorylessScheduler()) {
331 stateChoicesJson[
"m"] = memoryState;
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);
344 if (model && model->hasChoiceLabeling()) {
345 auto choiceLabels = model->getChoiceLabeling().getLabelsOfChoice(globalChoiceIndex);
346 choiceJson[
"labels"] = std::vector<std::string>(choiceLabels.begin(), choiceLabels.end());
348 choiceJson[
"index"] = globalChoiceIndex;
349 choiceJson[
"prob"] = storm::utility::convertNumber<storm::RationalNumber>(choiceProbPair.second);
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();
361 if (model && model->hasStateValuations()) {
362 updateJson[
"s'"] = model->getStateValuations().template toJson<storm::RationalNumber>(entryIt->getColumn());
364 updateJson[
"s'"] = entryIt->getColumn();
367 updateJson[
"m'"] = this->memoryStructure->getSuccessorMemoryState(memoryState, entryIt - model->getTransitionMatrix().begin());
368 choiceJson[
"memory-updates"].push_back(std::move(updateJson));
372 choicesJson.push_back(std::move(choiceJson));
375 choicesJson =
"undefined";
377 stateChoicesJson[
"c"] = std::move(choicesJson);
378 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.
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.
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.
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.