You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

273 lines
14 KiB

#include "src/storage/bisimulation/Partition.h"
#include <iostream>
#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<storm::storage::sparse::state_type> 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<storm::storage::sparse::state_type>::iterator first, std::vector<storm::storage::sparse::state_type>::iterator last) {
for (; first != last; ++first) {
this->stateToBlockMapping[*first] = &block;
}
}
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<storm::storage::sparse::state_type>::const_iterator Partition::begin(Block const& block) const {
return this->states.begin() + block.getBeginIndex();
}
std::vector<storm::storage::sparse::state_type>::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<bool (storm::storage::sparse::state_type, storm::storage::sparse::state_type)> const& lessFunction, std::function<bool (storm::storage::sparse::state_type, storm::storage::sparse::state_type)> 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<bool (storm::storage::sparse::state_type, storm::storage::sparse::state_type)> const& lessFunction, std::function<bool (storm::storage::sparse::state_type, storm::storage::sparse::state_type)> 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<storm::storage::sparse::state_type>::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<Block> const& Partition::getBlocks() const {
return this->blocks;
}
std::vector<Block>& 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();
}
}
}
}