#include "src/storage/bisimulation/Partition.h" #include #include "src/utility/macros.h" #include "src/exceptions/InvalidArgumentException.h" namespace storm { namespace storage { namespace bisimulation { Partition::Partition(std::size_t numberOfStates) : stateToBlockMapping(numberOfStates), states(numberOfStates), positions(numberOfStates) { blocks.emplace_back(0, numberOfStates, nullptr, nullptr, blocks.size()); // Set up the different parts of the internal structure. for (storm::storage::sparse::state_type state = 0; state < numberOfStates; ++state) { states[state] = state; positions[state] = state; stateToBlockMapping[state] = &blocks.back(); } } Partition::Partition(std::size_t numberOfStates, storm::storage::BitVector const& prob0States, storm::storage::BitVector const& prob1States, boost::optional representativeProb1State) : stateToBlockMapping(numberOfStates), states(numberOfStates), positions(numberOfStates) { storm::storage::sparse::state_type position = 0; Block* firstBlock = nullptr; Block* secondBlock = nullptr; Block* thirdBlock = nullptr; if (!prob0States.empty()) { blocks.emplace_back(0, prob0States.getNumberOfSetBits(), nullptr, nullptr, blocks.size()); firstBlock = &blocks[0]; for (auto state : prob0States) { states[position] = state; positions[state] = position; stateToBlockMapping[state] = firstBlock; ++position; } firstBlock->setAbsorbing(true); } if (!prob1States.empty()) { blocks.emplace_back(position, position + prob1States.getNumberOfSetBits(), firstBlock, nullptr, blocks.size()); secondBlock = &blocks[1]; for (auto state : prob1States) { states[position] = state; positions[state] = position; stateToBlockMapping[state] = secondBlock; ++position; } secondBlock->setAbsorbing(true); secondBlock->setRepresentativeState(representativeProb1State.get()); } storm::storage::BitVector otherStates = ~(prob0States | prob1States); if (!otherStates.empty()) { blocks.emplace_back(position, numberOfStates, secondBlock, nullptr, blocks.size()); thirdBlock = &blocks[2]; for (auto state : otherStates) { states[position] = state; positions[state] = position; stateToBlockMapping[state] = thirdBlock; ++position; } } } void Partition::swapStates(storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { std::swap(this->states[this->positions[state1]], this->states[this->positions[state2]]); std::swap(this->positions[state1], this->positions[state2]); } void Partition::swapStatesAtPositions(storm::storage::sparse::state_type position1, storm::storage::sparse::state_type position2) { storm::storage::sparse::state_type state1 = this->states[position1]; storm::storage::sparse::state_type state2 = this->states[position2]; std::swap(this->states[position1], this->states[position2]); this->positions[state1] = position2; this->positions[state2] = position1; } storm::storage::sparse::state_type const& Partition::getPosition(storm::storage::sparse::state_type state) const { return this->positions[state]; } void Partition::setPosition(storm::storage::sparse::state_type state, storm::storage::sparse::state_type position) { this->positions[state] = position; } storm::storage::sparse::state_type const& Partition::getState(storm::storage::sparse::state_type position) const { return this->states[position]; } void Partition::mapStatesToBlock(Block& block, std::vector::iterator first, std::vector::iterator last) { for (; first != last; ++first) { this->stateToBlockMapping[*first] = █ } } void Partition::mapStatesToPositions(Block const& block) { storm::storage::sparse::state_type position = block.getBeginIndex(); for (auto stateIt = this->begin(block), stateIte = this->end(block); stateIt != stateIte; ++stateIt, ++position) { this->positions[*stateIt] = position; } } Block& Partition::getBlock(storm::storage::sparse::state_type state) { return *this->stateToBlockMapping[state]; } Block const& Partition::getBlock(storm::storage::sparse::state_type state) const { return *this->stateToBlockMapping[state]; } std::vector::const_iterator Partition::begin(Block const& block) const { return this->states.begin() + block.getBeginIndex(); } std::vector::const_iterator Partition::end(Block const& block) const { return this->states.begin() + block.getEndIndex(); } Block& Partition::splitBlock(Block& block, storm::storage::sparse::state_type position) { STORM_LOG_THROW(position >= block.getBeginIndex() && position <= block.getEndIndex(), storm::exceptions::InvalidArgumentException, "Cannot split block at illegal position."); // In case one of the resulting blocks would be empty, we simply return the current block and do not create // a new one. if (position == block.getBeginIndex() || position == block.getEndIndex()) { return block; } // Actually create the new block. blocks.emplace_back(block.getBeginIndex(), position, block.getPreviousBlockPointer(), &block, blocks.size()); Block& newBlock = blocks.back(); // Resize the current block appropriately. block.setBeginIndex(position); // Mark both blocks as splitters. block.markAsSplitter(); newBlock.markAsSplitter(); // Update the mapping of the states in the newly created block. this->mapStatesToBlock(newBlock, this->begin(newBlock), this->end(newBlock)); return newBlock; } void Partition::splitBlock(Block& block, std::function const& lessFunction, std::function const& changedFunction) { // Sort the range of the block such that all states that have the label are moved to the front. std::sort(this->begin(block), this->end(block), lessFunction); // Update the positions vector. mapStatesToPositions(block); // Now we can check whether the block needs to be split, which is the case iff the changed function returns // true for the first and last element of the remaining state range. storm::storage::sparse::state_type begin = block.getBeginIndex(); storm::storage::sparse::state_type end = block.getEndIndex() - 1; while (changedFunction(begin, end)) { // Now we scan for the first state in the block for which the changed function returns true. // Note that we do not have to check currentIndex for staying within bounds, because we know the matching // state is within bounds. storm::storage::sparse::state_type currentIndex = begin + 1; while (begin != end && !changedFunction(states[begin], states[currentIndex])) { ++currentIndex; } begin = currentIndex; this->splitBlock(block, currentIndex); } } void Partition::split(std::function const& lessFunction, std::function const& changedFunction) { for (auto& block : blocks) { splitBlock(block, lessFunction, changedFunction); } } Block& Partition::splitStates(Block& block, storm::storage::BitVector const& states) { // Sort the range of the block such that all states that have the label are moved to the front. std::sort(this->begin(block), this->end(block), [&states] (storm::storage::sparse::state_type const& a, storm::storage::sparse::state_type const& b) { return states.get(a) && !states.get(b); } ); // Update the positions vector. mapStatesToPositions(block); // Now we can find the first position in the block that does not have the label and create new blocks. std::vector::const_iterator it = std::find_if(this->begin(block), this->end(block), [&states] (storm::storage::sparse::state_type const& a) { return !states.get(a); }); if (it != this->begin(block) && it != this->end(block)) { auto cutPoint = std::distance(this->states.cbegin(), it); return this->splitBlock(block, cutPoint); } else { return block; } } void Partition::splitStates(storm::storage::BitVector const& states) { for (auto& block : blocks) { splitStates(block, states); } } void Partition::sortBlock(Block const& block) { std::sort(this->begin(block), this->end(block), [] (storm::storage::sparse::state_type const& a, storm::storage::sparse::state_type const& b) { return a < b; }); mapStatesToPositions(block); } Block& Partition::insertBlock(Block& block) { // Find the beginning of the new block. storm::storage::sparse::state_type begin = block.hasPreviousBlock() ? block.getPreviousBlock().getEndIndex() : 0; // Actually insert the new block. blocks.emplace_back(begin, block.getBeginIndex(), block.getPreviousBlockPointer(), &block, blocks.size()); Block& newBlock = blocks.back(); // Update the mapping of the states in the newly created block. for (auto it = this->begin(newBlock), ite = this->end(newBlock); it != ite; ++it) { stateToBlockMapping[*it] = &newBlock; } return newBlock; } std::vector const& Partition::getBlocks() const { return this->blocks; } std::vector& Partition::getBlocks() { return this->blocks; } bool Partition::check() const { for (uint_fast64_t state = 0; state < this->positions.size(); ++state) { STORM_LOG_ASSERT(this->states[this->positions[state]] == state, "Position mapping corrupted."); } for (auto const& block : this->blocks) { STORM_LOG_ASSERT(block.check(), "Block corrupted."); for (auto stateIt = this->begin(block), stateIte = this->end(block); stateIt != stateIte; ++stateIt) { STORM_LOG_ASSERT(this->stateToBlockMapping[*stateIt] == &block, "Block mapping corrupted."); } } return true; } void Partition::print() const { for (auto const& block : this->blocks) { block.print(*this); } std::cout << "states in partition" << std::endl; for (auto const& state : states) { std::cout << state << " "; } std::cout << std::endl << "positions: " << std::endl; for (auto const& index : positions) { std::cout << index << " "; } std::cout << std::endl << "state to block mapping: " << std::endl; for (auto const& block : stateToBlockMapping) { std::cout << block << "[" << block->getId() <<"] "; } std::cout << std::endl; std::cout << "size: " << blocks.size() << std::endl; STORM_LOG_ASSERT(this->check(), "Partition corrupted."); } std::size_t Partition::size() const { return blocks.size(); } } } }