5#include <unordered_map>
19using namespace bisimulation;
21template<
typename ModelType>
25 probabilitiesToCurrentSplitter(model.getNumberOfStates(),
storm::utility::zero<
ValueType>()) {
29template<
typename ModelType>
34template<
typename ModelType>
36 std::vector<storm::storage::sparse::state_type> stateStack;
37 stateStack.reserve(this->model.getNumberOfStates());
40 uint_fast64_t currentSize = this->partition.size();
41 for (uint_fast64_t blockIndex = 0; blockIndex < currentSize; ++blockIndex) {
42 auto& block = *this->partition.getBlocks()[blockIndex];
43 nondivergentStates.clear();
45 for (
auto stateIt = this->partition.begin(block), stateIte = this->partition.end(block); stateIt != stateIte; ++stateIt) {
46 if (nondivergentStates.get(*stateIt)) {
52 bool isDirectlyNonDivergent =
false;
53 for (
auto const& successor : this->model.getTransitionMatrix().getRowGroup(*stateIt)) {
56 if (this->partition.getBlock(successor.getColumn()) != block) {
57 isDirectlyNonDivergent =
true;
62 if (isDirectlyNonDivergent) {
63 stateStack.push_back(*stateIt);
65 while (!stateStack.empty()) {
67 stateStack.pop_back();
68 nondivergentStates.set(currentState);
70 for (
auto const& predecessor : this->backwardTransitions.getRow(currentState)) {
71 if (this->partition.getBlock(predecessor.getColumn()) == block && !nondivergentStates.get(predecessor.getColumn())) {
72 stateStack.push_back(predecessor.getColumn());
79 if (!nondivergentStates.empty() && nondivergentStates.getNumberOfSetBits() != block.getNumberOfStates()) {
81 this->partition.splitStates(block, nondivergentStates);
86 block.data().setAbsorbing(
true);
87 }
else if (nondivergentStates.empty()) {
89 block.data().setAbsorbing(
true);
94template<
typename ModelType>
95void DeterministicModelBisimulationDecomposition<ModelType>::initializeSilentProbabilities() {
96 silentProbabilities.resize(this->model.getNumberOfStates(), storm::utility::zero<ValueType>());
98 Block<BlockDataType>
const* currentBlockPtr = &this->partition.getBlock(state);
99 for (
auto const& successorEntry : this->model.getTransitionMatrix().getRowGroup(state)) {
100 if (&this->partition.getBlock(successorEntry.getColumn()) == currentBlockPtr) {
101 silentProbabilities[state] += successorEntry.getValue();
107template<
typename ModelType>
108void DeterministicModelBisimulationDecomposition<ModelType>::initializeWeakDtmcBisimulation() {
111 this->splitOffDivergentStates();
112 this->initializeSilentProbabilities();
115template<
typename ModelType>
116void DeterministicModelBisimulationDecomposition<ModelType>::postProcessInitialPartition() {
118 this->initializeWeakDtmcBisimulation();
121 if (this->options.getKeepRewards() && this->model.hasRewardModel() && this->options.getType() ==
BisimulationType::Weak) {
127 std::optional<std::vector<ValueType>>
const& optionalStateRewardVector = this->model.getUniqueRewardModel().getOptionalStateRewardVector();
128 std::optional<std::vector<ValueType>>
const& optionalStateActionRewardVector = this->model.getUniqueRewardModel().getOptionalStateActionRewardVector();
129 for (
auto& block : this->partition.getBlocks()) {
130 auto state = *this->partition.begin(*block);
131 block->data().setHasRewards((optionalStateRewardVector && !
storm::utility::isZero(optionalStateRewardVector.value()[state])) ||
132 (optionalStateActionRewardVector && !
storm::utility::isZero(optionalStateActionRewardVector.value()[state])));
137template<
typename ModelType>
140 postProcessInitialPartition();
143template<
typename ModelType>
146 postProcessInitialPartition();
149template<
typename ModelType>
152 return probabilitiesToCurrentSplitter[state];
155template<
typename ModelType>
157 return this->comparator.isOne(silentProbabilities[state]);
160template<
typename ModelType>
162 return !this->comparator.isZero(silentProbabilities[state]);
165template<
typename ModelType>
168 return silentProbabilities[state];
171template<
typename ModelType>
172void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlockOfSplitterStrong(
173 bisimulation::Block<BlockDataType>& block, std::vector<bisimulation::Block<BlockDataType>*>& splitterQueue) {
174 STORM_LOG_TRACE(
"Refining predecessor " << block.getId() <<
" of splitter");
177 Block<BlockDataType>* blockToRefineProbabilistically = █
181 if (block.getBeginIndex() != block.data().marker1() && block.getEndIndex() != block.data().marker1()) {
183 this->partition.splitBlock(block, block.data().marker1());
184 blockToRefineProbabilistically = block.getPreviousBlockPointer();
187 blockToRefineProbabilistically->data().setHasRewards(block.data().hasRewards());
190 split |= this->partition.splitBlock(
191 *blockToRefineProbabilistically,
193 return this->comparator.isLess(getProbabilityToSplitter(state1), getProbabilityToSplitter(state2));
195 [&splitterQueue, &block](Block<BlockDataType>& newBlock) {
196 splitterQueue.emplace_back(&newBlock);
197 newBlock.data().setSplitter();
200 newBlock.data().setHasRewards(block.data().hasRewards());
205 if (split && !blockToRefineProbabilistically->data().splitter()) {
206 splitterQueue.emplace_back(blockToRefineProbabilistically);
207 blockToRefineProbabilistically->data().setSplitter();
211template<
typename ModelType>
212void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterStrong(
213 std::list<Block<BlockDataType>*>
const& predecessorBlocks, std::vector<bisimulation::Block<BlockDataType>*>& splitterQueue) {
214 for (
auto block : predecessorBlocks) {
215 refinePredecessorBlockOfSplitterStrong(*block, splitterQueue);
218 block->resetMarkers();
221 block->data().setNeedsRefinement(
false);
225template<
typename ModelType>
226bool DeterministicModelBisimulationDecomposition<ModelType>::possiblyNeedsRefinement(bisimulation::Block<BlockDataType>
const& predecessorBlock)
const {
227 return predecessorBlock.getNumberOfStates() > 1 && !predecessorBlock.data().absorbing();
230template<
typename ModelType>
232 bisimulation::Block<BlockDataType>
const& predecessorBlock,
233 ValueType
const& value) {
234 STORM_LOG_TRACE(
"Increasing probability of " << predecessor <<
" to splitter by " << value <<
".");
238 if (predecessorPosition >= predecessorBlock.data().marker1()) {
240 probabilitiesToCurrentSplitter[predecessor] = value;
243 probabilitiesToCurrentSplitter[predecessor] += value;
247template<
typename ModelType>
249 bisimulation::Block<BlockDataType>& predecessorBlock) {
250 this->partition.swapStates(predecessor, this->partition.getState(predecessorBlock.data().marker1()));
251 predecessorBlock.data().incrementMarker1();
254template<
typename ModelType>
256 bisimulation::Block<BlockDataType>& predecessorBlock) {
257 this->partition.swapStates(predecessor, this->partition.getState(predecessorBlock.data().marker2()));
258 predecessorBlock.data().incrementMarker2();
261template<
typename ModelType>
263 bisimulation::Block<BlockDataType>& predecessorBlock,
265 uint_fast64_t& elementsToSkip) {
269 if (predecessorPosition <= currentPositionInSplitter + elementsToSkip) {
270 this->partition.swapStates(predecessor, this->partition.getState(predecessorBlock.data().marker1()));
271 predecessorBlock.data().incrementMarker1();
276 if (predecessorBlock.data().marker2() == predecessorBlock.data().marker1()) {
277 this->partition.swapStatesAtPositions(predecessorBlock.data().marker2(), predecessorPosition);
278 this->partition.swapStatesAtPositions(predecessorPosition, currentPositionInSplitter + elementsToSkip + 1);
280 this->partition.swapStatesAtPositions(predecessorBlock.data().marker2(), predecessorPosition);
281 this->partition.swapStatesAtPositions(predecessorPosition, predecessorBlock.data().marker1());
282 this->partition.swapStatesAtPositions(predecessorPosition, currentPositionInSplitter + elementsToSkip + 1);
287 predecessorBlock.data().incrementMarker1();
288 predecessorBlock.data().incrementMarker2();
292template<
typename ModelType>
293void DeterministicModelBisimulationDecomposition<ModelType>::exploreRemainingStatesOfSplitter(
294 bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*>& predecessorBlocks) {
295 for (
auto splitterIt = this->partition.begin(splitter),
296 splitterIte = this->partition.begin(splitter) + (splitter.data().marker2() - splitter.getBeginIndex());
297 splitterIt != splitterIte; ++splitterIt) {
300 for (
auto const& predecessorEntry : this->backwardTransitions.getRow(currentState)) {
302 Block<BlockDataType>& predecessorBlock = this->partition.getBlock(predecessor);
305 if (!possiblyNeedsRefinement(predecessorBlock)) {
316 increaseProbabilityToSplitter(predecessor, predecessorBlock, predecessorEntry.getValue());
320 if (predecessorPosition >= predecessorBlock.data().marker1()) {
321 moveStateToMarker1(predecessor, predecessorBlock);
326 insertIntoPredecessorList(predecessorBlock, predecessorBlocks);
332 splitter.data().setMarker2(splitter.getBeginIndex());
335template<
typename ModelType>
336void DeterministicModelBisimulationDecomposition<ModelType>::updateSilentProbabilitiesBasedOnProbabilitiesToSplitter(
337 bisimulation::Block<BlockDataType>& block) {
339 for (
auto stateIt = this->partition.begin(block), stateIte = this->partition.begin() + block.data().marker1(); stateIt != stateIte; ++stateIt) {
340 silentProbabilities[*stateIt] = probabilitiesToCurrentSplitter[*stateIt];
343 for (
auto stateIt = this->partition.begin() + block.data().marker1(), stateIte = this->partition.end(block); stateIt != stateIte; ++stateIt) {
344 silentProbabilities[*stateIt] = storm::utility::zero<ValueType>();
348template<
typename ModelType>
349void DeterministicModelBisimulationDecomposition<ModelType>::updateSilentProbabilitiesBasedOnTransitions(bisimulation::Block<BlockDataType>& block) {
350 for (
auto stateIt = this->partition.begin(block), stateIte = this->partition.end(block); stateIt != stateIte; ++stateIt) {
351 if (hasNonZeroSilentProbability(*stateIt)) {
352 ValueType newSilentProbability = storm::utility::zero<ValueType>();
353 for (
auto const& successorEntry : this->model.getTransitionMatrix().getRow(*stateIt)) {
354 if (this->partition.getBlock(successorEntry.getColumn()) == block) {
355 newSilentProbability += successorEntry.getValue();
358 silentProbabilities[*stateIt] = newSilentProbability;
363template<
typename ModelType>
364void DeterministicModelBisimulationDecomposition<ModelType>::computeConditionalProbabilitiesForNonSilentStates(bisimulation::Block<BlockDataType>& block) {
365 for (
auto stateIt = this->partition.begin() + block.getBeginIndex(), stateIte = this->partition.begin() + block.data().marker1(); stateIt != stateIte;
367 if (!this->comparator.isOne(getSilentProbability(*stateIt))) {
368 probabilitiesToCurrentSplitter[*stateIt] /= storm::utility::one<ValueType>() - getSilentProbability(*stateIt);
373template<
typename ModelType>
374std::vector<uint_fast64_t> DeterministicModelBisimulationDecomposition<ModelType>::computeNonSilentBlocks(bisimulation::Block<BlockDataType>& block) {
376 return probabilitiesToCurrentSplitter[state1] < probabilitiesToCurrentSplitter[state2];
378 this->partition.sortRange(block.getBeginIndex(), block.data().marker1(), less);
379 return this->partition.computeRangesOfEqualValue(block.getBeginIndex(), block.data().marker1(), less);
382template<
typename ModelType>
383std::vector<storm::storage::BitVector> DeterministicModelBisimulationDecomposition<ModelType>::computeWeakStateLabelingBasedOnNonSilentBlocks(
384 bisimulation::Block<BlockDataType>
const& block, std::vector<uint_fast64_t>
const& nonSilentBlockIndices) {
387 std::vector<storm::storage::BitVector> stateLabels(block.getNumberOfStates(),
storm::storage::BitVector(nonSilentBlockIndices.size() - 1));
389 std::vector<storm::storage::sparse::state_type> stateStack;
390 stateStack.reserve(block.getNumberOfStates());
391 for (uint_fast64_t stateClassIndex = 0; stateClassIndex < nonSilentBlockIndices.size() - 1; ++stateClassIndex) {
392 for (
auto stateIt = this->partition.begin() + nonSilentBlockIndices[stateClassIndex],
393 stateIte = this->partition.begin() + nonSilentBlockIndices[stateClassIndex + 1];
394 stateIt != stateIte; ++stateIt) {
395 stateStack.push_back(*stateIt);
396 stateLabels[this->partition.getPosition(*stateIt) - block.getBeginIndex()].set(stateClassIndex);
397 while (!stateStack.empty()) {
399 stateStack.pop_back();
401 for (
auto const& predecessorEntry : this->backwardTransitions.getRow(currentState)) {
410 if (this->partition.getBlock(predecessor) == block && isSilent(predecessor) &&
411 !stateLabels[this->partition.getPosition(predecessor) - block.getBeginIndex()].get(stateClassIndex)) {
412 stateStack.push_back(predecessor);
413 stateLabels[this->partition.getPosition(predecessor) - block.getBeginIndex()].set(stateClassIndex);
423template<
typename ModelType>
424void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlockOfSplitterWeak(
425 bisimulation::Block<BlockDataType>& block, std::vector<bisimulation::Block<BlockDataType>*>& splitterQueue) {
428 computeConditionalProbabilitiesForNonSilentStates(block);
431 std::vector<uint_fast64_t> nonSilentBlockIndices = computeNonSilentBlocks(block);
432 std::vector<storm::storage::BitVector> weakStateLabels = computeWeakStateLabelingBasedOnNonSilentBlocks(block, nonSilentBlockIndices);
438 auto split = this->partition.splitBlock(
441 return weakStateLabels[this->partition.getPosition(state1) - originalBlockIndex] <
442 weakStateLabels[this->partition.getPosition(state2) - originalBlockIndex];
444 [
this, &splitterQueue, &block](bisimulation::Block<BlockDataType>& newBlock) {
445 updateSilentProbabilitiesBasedOnTransitions(newBlock);
448 newBlock.data().setSplitter();
449 splitterQueue.emplace_back(&newBlock);
452 newBlock.data().setHasRewards(block.data().hasRewards());
457 updateSilentProbabilitiesBasedOnTransitions(block);
459 if (!block.data().splitter()) {
461 block.data().setSplitter();
462 splitterQueue.emplace_back(&block);
467template<
typename ModelType>
468void DeterministicModelBisimulationDecomposition<ModelType>::refinePredecessorBlocksOfSplitterWeak(
469 bisimulation::Block<BlockDataType>& splitter, std::list<bisimulation::Block<BlockDataType>*>
const& predecessorBlocks,
470 std::vector<bisimulation::Block<BlockDataType>*>& splitterQueue) {
471 for (
auto block : predecessorBlocks) {
472 if (block->data().hasRewards()) {
473 refinePredecessorBlockOfSplitterStrong(*block, splitterQueue);
475 if (*block != splitter) {
476 refinePredecessorBlockOfSplitterWeak(*block, splitterQueue);
482 block->resetMarkers();
483 block->data().setNeedsRefinement(
false);
487template<
typename ModelType>
488void DeterministicModelBisimulationDecomposition<ModelType>::insertIntoPredecessorList(bisimulation::Block<BlockDataType>& predecessorBlock,
489 std::list<bisimulation::Block<BlockDataType>*>& predecessorBlocks) {
491 if (!predecessorBlock.data().needsRefinement()) {
492 predecessorBlocks.emplace_back(&predecessorBlock);
493 predecessorBlock.data().setNeedsRefinement();
497template<
typename ModelType>
517 std::list<Block<BlockDataType>*> predecessorBlocks;
519 bool splitterIsPredecessorBlock =
false;
520 for (
auto splitterIt = this->partition.begin(splitter), splitterIte = this->partition.end(splitter); splitterIt != splitterIte;
521 ++splitterIt, ++currentPosition) {
524 uint_fast64_t elementsToSkip = 0;
525 for (
auto const& predecessorEntry : this->backwardTransitions.getRow(currentState)) {
531 if (!possiblyNeedsRefinement(predecessorBlock)) {
542 increaseProbabilityToSplitter(predecessor, predecessorBlock, predecessorEntry.getValue());
545 if (predecessorPosition >= predecessorBlock.
data().marker1()) {
547 if (predecessorBlock != splitter) {
548 moveStateToMarker1(predecessor, predecessorBlock);
551 splitterIsPredecessorBlock =
true;
552 moveStateInSplitter(predecessor, predecessorBlock, currentPosition, elementsToSkip);
555 insertIntoPredecessorList(predecessorBlock, predecessorBlocks);
560 splitterIt += elementsToSkip;
561 currentPosition += elementsToSkip;
566 if (splitterIsPredecessorBlock) {
567 exploreRemainingStatesOfSplitter(splitter, predecessorBlocks);
574 refinePredecessorBlocksOfSplitterStrong(predecessorBlocks, splitterQueue);
578 if (splitterIsPredecessorBlock) {
579 updateSilentProbabilitiesBasedOnProbabilitiesToSplitter(splitter);
582 refinePredecessorBlocksOfSplitterWeak(splitter, predecessorBlocks, splitterQueue);
586template<
typename ModelType>
598 std::set<std::string> atomicPropositionsSet = this->options.respectedAtomicPropositions.get();
599 atomicPropositionsSet.insert(
"init");
600 std::vector<std::string> atomicPropositions = std::vector<std::string>(atomicPropositionsSet.begin(), atomicPropositionsSet.end());
601 for (
auto const& ap : atomicPropositions) {
606 std::optional<std::vector<ValueType>> stateRewards;
607 if (this->options.getKeepRewards() && this->model.hasRewardModel()) {
608 stateRewards = std::vector<ValueType>(this->blocks.size());
612 for (uint_fast64_t blockIndex = 0; blockIndex < this->blocks.size(); ++blockIndex) {
613 auto const& block = this->blocks[blockIndex];
622 for (
auto const& state : block) {
623 if (!isSilent(state)) {
624 representativeState = state;
633 if (oldBlock.
data().absorbing()) {
634 builder.
addNextValue(blockIndex, blockIndex, storm::utility::one<ValueType>());
637 if (oldBlock.
data().hasRepresentativeState()) {
638 representativeState = oldBlock.
data().representativeState();
643 for (
auto const& ap : atomicPropositions) {
644 if (this->model.getStateLabeling().getStateHasLabel(ap, representativeState)) {
650 std::map<storm::storage::sparse::state_type, ValueType> blockProbability;
651 for (
auto const& entry : this->model.getTransitionMatrix().getRow(representativeState)) {
659 auto probIterator = blockProbability.find(targetBlock);
660 if (probIterator != blockProbability.end()) {
661 probIterator->second += entry.getValue();
663 blockProbability[targetBlock] = entry.getValue();
668 for (
auto const& probabilityEntry : blockProbability) {
670 !oldBlock.
data().hasRewards()) {
671 builder.
addNextValue(blockIndex, probabilityEntry.first,
672 probabilityEntry.second / (storm::utility::one<ValueType>() - getSilentProbability(representativeState)));
674 builder.
addNextValue(blockIndex, probabilityEntry.first, probabilityEntry.second);
680 for (
auto const& ap : atomicPropositions) {
681 if (this->model.getStateLabeling().getStateHasLabel(ap, representativeState)) {
689 if (this->options.getKeepRewards() && this->model.hasRewardModel()) {
690 auto const& rewardModel = this->model.getUniqueRewardModel();
691 if (rewardModel.hasStateRewards()) {
692 stateRewards.value()[blockIndex] = rewardModel.getStateRewardVector()[representativeState];
694 if (rewardModel.hasStateActionRewards()) {
695 stateRewards.value()[blockIndex] += rewardModel.getStateActionRewardVector()[representativeState];
701 for (
auto initialState : this->model.getInitialStates()) {
707 std::unordered_map<std::string, typename ModelType::RewardModelType> rewardModels;
708 if (this->options.getKeepRewards() && this->model.hasRewardModel()) {
709 STORM_LOG_THROW(this->model.hasUniqueRewardModel(), storm::exceptions::IllegalFunctionCallException,
"Cannot preserve more than one reward model.");
710 typename std::unordered_map<std::string, typename ModelType::RewardModelType>::const_iterator nameRewardModelPair =
711 this->model.getRewardModels().begin();
712 rewardModels.insert(std::make_pair(nameRewardModelPair->first,
typename ModelType::RewardModelType(stateRewards)));
716 this->quotient = std::shared_ptr<ModelType>(
new ModelType(builder.
build(), std::move(newLabeling), std::move(rewardModels)));
void addLabel(std::string const &label)
Adds a new label to the labelings.
This class manages the labeling of the state space with a number of (atomic) labels.
void addLabelToState(std::string const &label, storm::storage::sparse::state_type state)
Adds a label to a given state.
This class is the superclass of all decompositions of a sparse model into its bisimulation quotient.
virtual void initializeMeasureDrivenPartition()
Creates the measure-driven initial partition for reaching psi states from phi states.
virtual void initializeLabelBasedPartition()
Initializes the initial partition based on all respected labels.
A bit vector that is internally represented as a vector of 64-bit values.
This class represents the decomposition of a deterministic model into its bisimulation quotient.
virtual void refinePartitionBasedOnSplitter(bisimulation::Block< BlockDataType > &splitter, std::vector< bisimulation::Block< BlockDataType > * > &splitterQueue) override
virtual void initializeLabelBasedPartition() override
Initializes the initial partition based on all respected labels.
virtual void initializeMeasureDrivenPartition() override
Creates the measure-driven initial partition for reaching psi states from phi states.
DeterministicModelBisimulationDecomposition(ModelType const &model, typename BisimulationDecomposition< ModelType, BlockDataType >::Options const &options=typename BisimulationDecomposition< ModelType, BlockDataType >::Options())
Computes the bisimulation relation for the given model.
ModelType::ValueType ValueType
virtual void buildQuotient() override
Builds the quotient model based on the previously computed equivalence classes (stored in the blocks ...
virtual std::pair< storm::storage::BitVector, storm::storage::BitVector > getStatesWithProbability01() override
Computes the set of states with probability 0/1 for satisfying phi until psi.
A class that can be used to build a sparse matrix by adding value by value.
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.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
storm::storage::sparse::state_type getBeginIndex() const
std::size_t getId() const
#define STORM_LOG_TRACE(message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01(storm::models::sparse::DeterministicModel< T > const &model, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 or 1, respectively, of satisfying phi until psi i...
bool isZero(ValueType const &a)