Skip to content

Changes to Storm for revised belief exploration - #1028

Merged
tquatmann merged 15 commits into
stormchecker:masterfrom
AlexBork:revbel-storm
Sep 4, 2026
Merged

Changes to Storm for revised belief exploration#1028
tquatmann merged 15 commits into
stormchecker:masterfrom
AlexBork:revbel-storm

Conversation

@AlexBork

Copy link
Copy Markdown
Contributor

This PR contains changes to Storm outside Storm-POMDP for the revised belief exploration implementation, see PR #1004.

  • Transformer for transition-based to action-based rewards by inserting intermediate states
  • Transformer for ValueTypes of sparse models
  • Getter for optional time bound in BoundedUntilFormula

Comment thread src/storm/logic/BoundedUntilFormula.cpp Outdated
Comment thread src/storm/transformer/SparseModelValueTypeTransformer.h Outdated
Comment thread src/storm/transformer/TransitionToActionRewardTransformer.h
}
switch (inputModel->getType()) {
case storm::models::ModelType::Dtmc:
return std::make_shared<storm::models::sparse::Dtmc<double>>(storm::models::sparse::Dtmc<double>(convertedComponents));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this swtich case is extremely ugly. Is this the standard way to do this? @tquatmann ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is buildModelFromComponents in storm/utility/builder.h.

We still need some switch case like this for the model-specific components (exit rates for MAs, player data for SMG etc

Comment thread src/storm/transformer/TransitionToActionRewardTransformer.cpp
@sjunges

sjunges commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Thanks for the changes. I have two more nitpicky comments and would love to get @tquatmann input on the case black.

@AlexBork

Copy link
Copy Markdown
Contributor Author

I added instantiations for interval models in the transformer; this required a rework of how the different, unique reward vectors are stored and identified. I decided to to implement a potentially slower, but more readable solution. I don't think this should be a bottleneck.

@tquatmann tquatmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! After looking into my comments, this PR should be good to go imo.

Comment on lines +22 to +24
if (!convertedComponents.transitionMatrix.isProbabilistic(precision)) {
convertedComponents.transitionMatrix.divideRowsInPlace(convertedComponents.transitionMatrix.getRowSumVector());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo, this should rather go through each row individually, compute the row sum and (if necessary) scale the matrix values.

Currently, this unnecessarily allocates memory for the entire rowSumVector and also touches matrix rows that are actually precise enough.

Comment on lines +36 to +41
std::vector<double> resultVector;
resultVector.reserve(rewardModel.getStateRewardVector().size());
for (auto const& oldValue : rewardModel.getStateRewardVector()) {
resultVector.push_back(storm::utility::convertNumber<double>(oldValue));
}
optionalStateRewardVector = resultVector;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified to

Suggested change
std::vector<double> resultVector;
resultVector.reserve(rewardModel.getStateRewardVector().size());
for (auto const& oldValue : rewardModel.getStateRewardVector()) {
resultVector.push_back(storm::utility::convertNumber<double>(oldValue));
}
optionalStateRewardVector = resultVector;
optionalStateRewardVector = storm::utility::vector::convertNumericVector<double>(rewardModel.getStateRewardVector());

(same below)

}
switch (inputModel->getType()) {
case storm::models::ModelType::Dtmc:
return std::make_shared<storm::models::sparse::Dtmc<double>>(storm::models::sparse::Dtmc<double>(convertedComponents));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is buildModelFromComponents in storm/utility/builder.h.

We still need some switch case like this for the model-specific components (exit rates for MAs, player data for SMG etc

Comment on lines +65 to +70
std::vector<double> resultVector;
resultVector.reserve(ctmc->getExitRateVector().size());
for (auto const& oldValue : ctmc->getExitRateVector()) {
resultVector.push_back(storm::utility::convertNumber<double>(oldValue));
}
convertedComponents.exitRates = resultVector;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<double> resultVector;
resultVector.reserve(ctmc->getExitRateVector().size());
for (auto const& oldValue : ctmc->getExitRateVector()) {
resultVector.push_back(storm::utility::convertNumber<double>(oldValue));
}
convertedComponents.exitRates = resultVector;

We provide the rates in the transition matrix. A dedicated exit rate vector should not be set and will be ignored in this case.
We do need to set rateTransitions = true to indicate that the transitionMatrix contains rates, not probabilities.

models::sparse::StochasticTwoPlayerGame<double>(convertedComponents));
}
default:
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentTypeException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentTypeException,
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IllegalArgumentTypeException is more of a storm::settings thing.

Comment on lines +188 to +190
if (oldRewardModel.hasStateRewards()) {
rewValue += oldRewardModel.getStateReward(oldState);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For continuous time models, state rewards are earned over time. Collapsing them together with the action rewards like this is usually incorrect. However, for discrete-time models, it's probably convenient to merge the rewards.

I suggest this change here:

Suggested change
if (oldRewardModel.hasStateRewards()) {
rewValue += oldRewardModel.getStateReward(oldState);
}
if (originalModel->isDiscreteTimeModel() && oldRewardModel.hasStateRewards()) {
rewValue += oldRewardModel.getStateReward(oldState);
}

and below something like

std::optional<std::vector<ValueType>> newStateRewards;
if (originalModel->isContinuousTimeModel() && oldRewardModel.hasStateRewards()) {
        newStateRewards.emplace(numStates, storm::utility::zero<ValueType>())
        for (uint64_t origState = 0; origState < originalModel->getNumberOfStates(); ++origState) {
            uint64_t const newState = originalToNewIndex[origState];
            newStateRewards.value()[newState] = oldRewardModel.getStateReward(oldState);
        }
}
RewardModelType newRewardModel(newStateRewards, std::move(newActionRewardVector));

auto const& transitions = originalModel->getTransitionMatrix();
for (uint64_t row = 0; row < transitions.getRowCount(); ++row) {
rewardTransitionIterator.forEachRowEntry(
row, true, [&incomingRewards](uint64_t column, RewardValueType, detail::MultiRewardVector<RewardValueType> const& rewards) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
row, true, [&incomingRewards](uint64_t column, RewardValueType, detail::MultiRewardVector<RewardValueType> const& rewards) {
row, true, [&incomingRewards](uint64_t column, ValueType, detail::MultiRewardVector<RewardValueType> const& rewards) {

@AlexBork

AlexBork commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the comments, I have now added the requested changes. For the switch-case in the ToDoubleTransformer, I use a single buildModelFromComponents now, but opted to still include all cases explicitly. This way, if new model types are added, the default is to throw an exception instead of silently accepting it, which may lead to erroneous behaviour.

@tquatmann tquatmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Just a very small nitpick.

Comment thread src/storm/transformer/TransitionToActionRewardTransformer.cpp Outdated
@tquatmann
tquatmann merged commit 9429df0 into stormchecker:master Sep 4, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants