27 using Block = std::span<ElementIndex const>;
35 if (lhs.size() < rhs.size()) {
38 if (lhs.size() > rhs.size()) {
41 return lhs.data() < rhs.data();
72 std::size_t
size()
const;
98 std::vector<uint64_t> containedBlockIndices;
182 template<
typename Func>
183 requires std::invocable<Func, Block>
194 template<
typename Func>
195 requires std::invocable<Func, Block>
198 auto superBlockEnd = getBlockIndex(superBlock) + superBlock.size();
199 for (BlockIndex blockStart = getBlockIndex(superBlock); blockStart < superBlockEnd;) {
201 blockStart += subBlock.size();
213 template<
typename SplittingOrder>
214 requires std::invocable<SplittingOrder, ElementIndex, ElementIndex>
230 template<
typename Order,
typename Condition>
231 requires std::invocable<Order, ElementIndex, ElementIndex> && std::invocable<Condition, ElementIndex, ElementIndex>
233 if (block.size() <= 1) {
239 auto const blockStart = getBlockIndex(block);
241 auto const blockEnd = blockStart + block.size();
242 std::sort(blockContents.begin() + blockStart, blockContents.begin() + blockEnd, less);
246 blockContentsInverse[blockContents[i]] = i;
250 if (!splitCondition(blockContents[blockStart], blockContents[blockEnd - 1])) {
255 auto getEndOfBlock = [
this, splitCondition, blockEnd](BlockIndex
const currIndex) {
256 for (
auto i = currIndex + 1; i < blockEnd; ++i) {
257 if (splitCondition(blockContents[currIndex], blockContents[i])) {
265 for (
auto newBlockIndex = blockStart; newBlockIndex < blockEnd;) {
266 auto const newBlockEnd = getEndOfBlock(newBlockIndex);
267 registerNewBlock(newBlockIndex, newBlockEnd);
268 newBlockIndex = newBlockEnd;
286 template<
typename Condition>
287 requires std::invocable<Condition, ElementIndex, ElementIndex>
290 if (block.size() <= 1) {
294 auto const blockStart = getBlockIndex(block);
295 auto const blockEnd = blockStart + block.size();
299 auto const partitionBlock = [
this, &condition, &blockEnd](BlockIndex
const start) {
301 auto const anchor = blockContents[start];
302 return partitionBlockContents(start + 1, blockEnd, [&condition, &anchor](
ElementIndex const element) {
return condition(anchor, element); });
305 for (uint64_t start = blockStart; start < blockEnd;) {
306 auto const currEnd = partitionBlock(start);
308 if (start == blockStart && currEnd == blockEnd) {
311 registerNewBlock(start, currEnd);
327 template<
typename SplittingPredicate>
328 requires std::predicate<SplittingPredicate, ElementIndex>
334 auto const blockStart = getBlockIndex(block);
335 auto const blockEnd = blockStart + block.size();
336 auto const l = partitionBlockContents(blockStart, blockEnd, f);
339 if (l == blockStart) {
340 return {
Block{}, block};
341 }
else if (l == blockEnd) {
342 return {block,
Block{}};
346 Block noBlock = registerNewBlock(blockStart, l);
347 Block yesBlock = registerNewBlock(l, blockEnd);
349 return {noBlock, yesBlock};
359 template<
typename SplitRange>
360 requires std::ranges::input_range<std::remove_reference_t<SplitRange>> &&
361 std::same_as<std::ranges::range_value_t<std::remove_reference_t<SplitRange>>,
ElementIndex>
366 auto const blockStart = getBlockIndex(block);
367 auto const blockEnd = blockStart + block.size();
371 auto yesBlockStart = blockEnd;
373 auto const src = blockContentsInverse[element];
374 if (src < blockStart || src >= yesBlockStart) {
379 std::swap(blockContents[src], blockContents[yesBlockStart]);
380 blockContentsInverse[blockContents[src]] = src;
381 blockContentsInverse[blockContents[yesBlockStart]] = yesBlockStart;
385 if (yesBlockStart == blockStart) {
386 return {
Block{}, block};
387 }
else if (yesBlockStart == blockEnd) {
388 return {block,
Block{}};
392 Block noBlock = registerNewBlock(blockStart, yesBlockStart);
393 Block yesBlock = registerNewBlock(yesBlockStart, blockEnd);
395 return {noBlock, yesBlock};
403 using BlockIndex = uint64_t;
409 template<
typename SplittingPredicate>
410 requires std::predicate<SplittingPredicate, ElementIndex>
411 BlockIndex partitionBlockContents(BlockIndex
const start, BlockIndex
const end, SplittingPredicate
const& f) {
420 while (l <= r && !f(std::as_const(blockContents[l]))) {
427 while (l < r && f(std::as_const(blockContents[r]))) {
435 std::swap(blockContents[l], blockContents[r]);
436 blockContentsInverse[blockContents[l]] = l;
437 blockContentsInverse[blockContents[r]] = r;
450 BlockIndex getBlockIndex(
Block const& block)
const;
456 Block getBlockFromIndex(BlockIndex blockIndex)
const;
466 Block registerNewBlock(BlockIndex
const start, BlockIndex
const end);
470 std::vector<ElementIndex> blockContents;
474 std::vector<BlockIndex> blockContentsInverse;
477 std::vector<BlockIndex> elementToBlockIndex;
481 std::vector<std::size_t> blockSizes;
484 uint64_t numBlocks = 0;
NonSuperBlockSet(Partition const &partition)
Creates an empty set associated with the given partition.
void insert(Block const &block)
Inserts the given block into the set.
Block pop()
Removes and returns an arbitrary block from the set.
bool contains(Block const &block) const
Represents a partition of a set of consecutive indices.
bool contains(Block const &block, ElementIndex element) const
bool splitBlockByClustering(Block const &block, Condition const &condition)
Splits the given block by anchor-based clustering: repeatedly picks the first not-yet-grouped element...
std::map< Block, T, BlockCompare > OrderedBlockMap
A map of blocks, ordered by their size (smallest first).
void forEachBlock(Func const &f) const
Applies the given function on each block in the partition.
uint64_t ElementIndex
The type used to index the elements of the partition.
std::size_t getNumberOfBlocks() const
Retrieves the number of blocks.
void forEachSubBlock(Block const &superBlock, Func const &f) const
Applies the given function on each block in the given super block.
bool isSameBlock(ElementIndex const &element1, ElementIndex const &element2) const
Partition(Partition const &other)=default
bool isBlockOfElement(Block const &block, ElementIndex const &element) const
std::size_t getNumberOfElements() const
Retrieves the number of elements.
bool splitBlockByOrder(Block const &block, SplittingOrder const &less)
Splits the given block according to the given order.
std::span< ElementIndex const > Block
A contiguous range of elements that form a (possibly proper super-) block of the partition.
bool isSubBlockOf(Block const &subblock, Block const &superblock) const
Block getBlockOfElement(ElementIndex element) const
Partition(Partition &&other) noexcept=default
bool splitBlockByOrder(Block const &block, Order const &less, Condition const &splitCondition)
Splits the given block according to the given order and splitting condition.
std::pair< Block, Block > splitBlockByRange(Block const &block, SplitRange &&r)
Splits the given block according to the given range of elements.
std::set< Block, BlockCompare > OrderedBlockSet
A set of blocks, ordered by their size (smallest first).
Block getUniversalBlock() const
bool isProperSuperBlock(Block const &block) const
Partition & operator=(Partition const &other)=default
Partition & operator=(Partition &&other)=default
bool isEqualBlock(Block const &lhs, Block const &rhs) const
bool checkBlockValidity(Block const &block) const
Checks if the given block is a valid block in the partition.
std::pair< Block, Block > splitBlockByPredicate(Block const &block, SplittingPredicate const &f)
Splits the given block according to the given predicate.
A bit vector that is internally represented as a vector of 64-bit values.
#define STORM_LOG_ASSERT(cond, message)
std::ostream & operator<<(std::ostream &os, const Partition &partition)
Orders blocks by their size (ascending) and, for equally sized blocks, by their location in memory.
bool operator()(Block const &lhs, Block const &rhs) const