26template<
typename StateType>
30 if (!stateToId.contains(cs)) {
31 return static_cast<StateType
>(this->
size());
33 return this->stateToId.getValue(cs);
36template<
typename StateType>
38 return this->stateToId.size();
41template<
typename ValueType,
typename RewardModelType,
typename StateType>
47template<
typename ValueType,
typename RewardModelType,
typename StateType>
50 : generator(generator), options(options), stateStorage(generator->getStateSize()) {
54template<
typename ValueType,
typename RewardModelType,
typename StateType>
62template<
typename ValueType,
typename RewardModelType,
typename StateType>
71template<
typename ValueType,
typename RewardModelType,
typename StateType>
75 switch (generator->getModelType()) {
89 STORM_LOG_THROW(
false, storm::exceptions::WrongFormatException,
"Error while creating model: cannot handle this model type.");
95template<
typename ValueType,
typename RewardModelType,
typename StateType>
96StateType ExplicitModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex(
CompressedState const& state) {
97 StateType newIndex =
static_cast<StateType
>(stateStorage.getNumberOfStates());
100 std::pair<StateType, std::size_t> actualIndexBucketPair = stateStorage.stateToId.findOrAddAndGetBucket(state, newIndex);
102 StateType actualIndex = actualIndexBucketPair.first;
104 if (actualIndex == newIndex) {
106 statesToExplore.emplace_front(state, actualIndex);
111 statesToExplore.emplace_back(state, actualIndex);
120template<
typename ValueType,
typename RewardModelType,
typename StateType>
125template<
typename ValueType,
typename RewardModelType,
typename StateType>
126void ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(
137 std::bind(&ExplicitModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex,
this, std::placeholders::_1);
143 stateRemapping = std::vector<uint_fast64_t>();
147 this->stateStorage.initialStateIndices = generator->getInitialStates(stateToIdCallback);
148 STORM_LOG_THROW(!this->stateStorage.initialStateIndices.empty(), storm::exceptions::WrongFormatException,
149 "The model does not have a single initial state.");
152 uint_fast64_t currentRowGroup = 0;
153 uint_fast64_t currentRow = 0;
155 auto timeOfStart = std::chrono::high_resolution_clock::now();
156 auto timeOfLastMessage = std::chrono::high_resolution_clock::now();
157 uint64_t numberOfExploredStates = 0;
158 uint64_t numberOfExploredStatesSinceLastMessage = 0;
164 while (!statesToExplore.empty()) {
167 StateType currentIndex = statesToExplore.front().second;
168 statesToExplore.pop_front();
173 stateRemapping.get()[currentIndex] = currentRowGroup;
176 if (currentIndex % 100000 == 0) {
180 generator->
load(currentState);
182 generator->addStateValuation(currentIndex, stateAndChoiceInformationBuilder.
stateValuations());
186 bool const stateLimitExceeded = options.explorationStateLimit.has_value() && stateStorage.getNumberOfStates() >= options.explorationStateLimit.value();
188 storm::generator::StateBehavior<ValueType, StateType>
const& behavior = stateLimitExceeded ? emptyBehavior : generator->expand(stateToIdCallback);
190 if (behavior.
empty()) {
194 STORM_LOG_THROW(options.fixDeadlocks, storm::exceptions::WrongFormatException,
195 "Error while creating sparse matrix from probabilistic program: found deadlock state ("
196 << generator->stateToString(currentState) <<
"). For fixing these, please provide the appropriate option.");
197 this->stateStorage.deadlockStateIndices.push_back(currentIndex);
199 if (stateLimitExceeded) {
201 this->stateStorage.unexploredStateIndices.push_back(currentIndex);
208 if (!generator->isDeterministicModel()) {
214 for (
auto& rewardModelBuilder : rewardModelBuilders) {
215 if (rewardModelBuilder.hasStateRewards()) {
219 if (rewardModelBuilder.hasStateActionRewards()) {
237 for (
auto& rewardModelBuilder : rewardModelBuilders) {
238 if (rewardModelBuilder.hasStateRewards()) {
239 rewardModelBuilder.addStateReward(*stateRewardIt);
245 if (!generator->isDeterministicModel()) {
250 bool firstChoiceOfState =
true;
251 for (
auto const& choice : behavior) {
254 for (
auto const& label : choice.getLabels()) {
255 stateAndChoiceInformationBuilder.
addChoiceLabel(label, currentRow);
264 "There is a state where different players have an enabled choice.");
265 if (firstChoiceOfState) {
274 for (
auto const& stateProbabilityPair : choice) {
275 transitionMatrixBuilder.
addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second);
279 auto choiceRewardIt = choice.getRewards().begin();
280 for (
auto& rewardModelBuilder : rewardModelBuilders) {
281 if (rewardModelBuilder.hasStateActionRewards()) {
282 rewardModelBuilder.addStateActionReward(*choiceRewardIt);
287 firstChoiceOfState =
false;
293 ++numberOfExploredStates;
294 if (generator->getOptions().isShowProgressSet()) {
295 ++numberOfExploredStatesSinceLastMessage;
297 auto now = std::chrono::high_resolution_clock::now();
298 auto durationSinceLastMessage = std::chrono::duration_cast<std::chrono::seconds>(now - timeOfLastMessage).count();
299 if (
static_cast<uint64_t
>(durationSinceLastMessage) >= generator->getOptions().getShowProgressDelay()) {
300 auto statesPerSecond = numberOfExploredStatesSinceLastMessage / durationSinceLastMessage;
301 auto durationSinceStart = std::chrono::duration_cast<std::chrono::seconds>(now - timeOfStart).count();
302 std::cout <<
"Explored " << numberOfExploredStates <<
" states in " << durationSinceStart <<
" seconds (currently " << statesPerSecond
303 <<
" states per second).\n";
304 timeOfLastMessage = std::chrono::high_resolution_clock::now();
305 numberOfExploredStatesSinceLastMessage = 0;
310 auto durationSinceStart = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - timeOfStart).count();
311 std::cout <<
"Explored " << numberOfExploredStates <<
" states in " << durationSinceStart <<
" seconds before abort.\n";
312 STORM_LOG_THROW(
false, storm::exceptions::AbortException,
"Aborted in state space exploration.");
321 std::vector<uint_fast64_t>
const& remapping = stateRemapping.get();
333 std::vector<StateType> newInitialStateIndices(this->stateStorage.initialStateIndices.size());
334 std::transform(this->stateStorage.initialStateIndices.begin(), this->stateStorage.initialStateIndices.end(), newInitialStateIndices.begin(),
335 [&remapping](StateType
const& state) { return remapping[state]; });
336 std::sort(newInitialStateIndices.begin(), newInitialStateIndices.end());
337 this->stateStorage.initialStateIndices = std::move(newInitialStateIndices);
340 this->stateStorage.stateToId.remap([&remapping](StateType
const& state) {
return remapping[state]; });
342 this->generator->remapStateIds([&remapping](StateType
const& state) {
return remapping[state]; });
346template<
typename ValueType,
typename RewardModelType,
typename StateType>
347storm::storage::sparse::ModelComponents<ValueType, RewardModelType> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents() {
350 bool deterministicModel = generator->isDeterministicModel();
353 storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0,
false, !deterministicModel, 0);
354 std::vector<RewardModelBuilder<typename RewardModelType::ValueType>> rewardModelBuilders;
355 for (uint64_t i = 0;
i < generator->getNumberOfRewardModels(); ++
i) {
356 rewardModelBuilders.emplace_back(generator->getRewardModelInformation(i));
359 stateAndChoiceInformationBuilder.
setBuildChoiceLabels(generator->getOptions().isBuildChoiceLabelsSet());
360 stateAndChoiceInformationBuilder.setBuildChoiceOrigins(generator->getOptions().isBuildChoiceOriginsSet());
363 stateAndChoiceInformationBuilder.setBuildStateValuations(generator->getOptions().isBuildStateValuationsSet());
365 buildMatrices(transitionMatrixBuilder, rewardModelBuilders, stateAndChoiceInformationBuilder);
368 storm::storage::sparse::ModelComponents<ValueType, RewardModelType> modelComponents(
370 std::unordered_map<std::string, RewardModelType>(), !generator->isDiscreteTimeModel());
374 if (generator->getOptions().getStochasticTolerance() != 0.0) {
379 uint_fast64_t numStates = modelComponents.transitionMatrix.getColumnCount();
380 uint_fast64_t numChoices = modelComponents.transitionMatrix.getRowCount();
383 for (
auto& rewardModelBuilder : rewardModelBuilders) {
384 modelComponents.rewardModels.emplace(rewardModelBuilder.getName(),
385 rewardModelBuilder.build(numChoices, modelComponents.transitionMatrix.getColumnCount(), numStates));
388 if (stateAndChoiceInformationBuilder.isBuildStatePlayerIndications()) {
389 modelComponents.statePlayerIndications = stateAndChoiceInformationBuilder.buildStatePlayerIndications(numStates);
390 modelComponents.playerNameToIndexMap = generator->getPlayerNameToIndexMap();
393 if (stateAndChoiceInformationBuilder.isBuildMarkovianStates()) {
394 modelComponents.markovianStates = stateAndChoiceInformationBuilder.buildMarkovianStates(numStates);
397 if (stateAndChoiceInformationBuilder.isBuildChoiceLabels()) {
398 modelComponents.choiceLabeling = stateAndChoiceInformationBuilder.buildChoiceLabeling(numChoices);
401 if (stateAndChoiceInformationBuilder.isBuildStateValuations()) {
402 modelComponents.stateValuations = std::move(stateAndChoiceInformationBuilder.stateValuations());
404 if (stateAndChoiceInformationBuilder.isBuildChoiceOrigins()) {
405 auto originData = stateAndChoiceInformationBuilder.buildDataOfChoiceOrigins(numChoices);
406 modelComponents.choiceOrigins = generator->generateChoiceOrigins(originData);
408 if (generator->isPartiallyObservable()) {
409 std::vector<uint32_t> classes(stateStorage.getNumberOfStates());
410 std::unordered_map<uint32_t, std::vector<std::pair<std::vector<std::string>, uint32_t>>> observationActions;
411 for (
auto const& bitVectorIndexPair : stateStorage.stateToId) {
412 uint32_t varObservation = generator->observabilityClass(bitVectorIndexPair.first);
413 classes[bitVectorIndexPair.second] = varObservation;
416 modelComponents.observabilityClasses = classes;
417 if (generator->getOptions().isBuildObservationValuationsSet()) {
418 modelComponents.observationValuations = generator->makeObservationValuation();
421 return modelComponents;
424template<
typename ValueType,
typename RewardModelType,
typename StateType>
425storm::models::sparse::StateLabeling ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() {
426 return generator->label(stateStorage, stateStorage.initialStateIndices, stateStorage.deadlockStateIndices, stateStorage.unexploredStateIndices);
ExplicitStateLookup< StateType > exportExplicitStateLookup() const
Export a wrapper that contains (a copy of) the internal information that maps states to ids.
ExplicitModelBuilder(std::shared_ptr< storm::generator::NextStateGenerator< ValueType, StateType > > const &generator, Options const &options=Options())
Creates an explicit model builder that uses the provided generator.
std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > build()
Convert the program given at construction time to an abstract model.
StateType lookup(std::map< storm::expressions::Variable, storm::expressions::Expression > const &stateDescription) const
Lookup state.
uint64_t size() const
How many states have been stored?
A structure that is used to keep track of a reward model currently being built.
bool empty() const
Retrieves whether the behavior is empty in the sense that there are no available choices.
bool wasExpanded() const
Retrieves whether the state was expanded.
std::vector< ValueType > const & getStateRewards() const
Retrieves the list of state rewards under selected reward models.
static BitVector load(std::string const &description)
A class that can be used to build a sparse matrix by adding value by value.
index_type getCurrentRowGroupCount() const
Retrieves the current row group count.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void replaceColumns(std::vector< index_type > const &replacements, index_type offset)
Replaces all columns with id > offset according to replacements.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
CompressedState createCompressedState(VariableInformation const &varInfo, std::map< storm::expressions::Variable, storm::expressions::Expression > const &stateDescription, bool checkOutOfBounds)
storm::storage::BitVector CompressedState
storm::builder::BuilderOptions NextStateGeneratorOptions
std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents< ValueType, RewardModelType > &&components)
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
TargetType convertNumber(SourceType const &number)
constexpr bool IsIntervalType
Helper to check if a type is an interval.
static const bool IsExact
Options()
Creates an object representing the default building options.
std::optional< StateType > explorationStateLimit
ExplorationOrder explorationOrder