10std::string blockToString(
auto const& block) {
11 std::ostringstream oss;
13 for (
bool first{
true};
auto const e : block) {
27 bool const expectedContainsActual =
28 std::all_of(actual.begin(), actual.end(), [&expected](
auto const& e) { return std::find(expected.begin(), expected.end(), e) != expected.end(); });
29 EXPECT_TRUE(expectedContainsActual) <<
"Content mismatch: " << blockToString(expected) <<
" vs. " << blockToString(actual);
30 bool const actualContainsExpected =
31 std::all_of(expected.begin(), expected.end(), [&actual](
auto const& e) { return std::find(actual.begin(), actual.end(), e) != actual.end(); });
32 EXPECT_TRUE(actualContainsExpected) <<
"Content mismatch: " << blockToString(expected) <<
" vs. " << blockToString(actual);
35 for (
auto const& e : expected) {
36 EXPECT_TRUE(partition.
contains(actual, e)) <<
"Element " << e <<
" not in block " << blockToString(actual);
39 return expectedContainsActual && actualContainsExpected;
42TEST(PartitionTest, EmptyPartition) {
46TEST(PartitionTest, Basic) {
52 for (
auto i = 0ul;
i < 10; ++
i) {
54 ASSERT_TRUE(partition.
checkBlockValidity(block)) <<
"Block " << blockToString(block) <<
" is not valid.";
55 EXPECT_TRUE(equalBlocks(partition, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, block));
63 ASSERT_TRUE(partition.
checkBlockValidity(odd)) <<
"Block " << blockToString(odd) <<
" is not valid.";
64 ASSERT_TRUE(partition.
checkBlockValidity(even)) <<
"Block " << blockToString(even) <<
" is not valid.";
65 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5, 7, 9}, odd));
66 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4, 6, 8}, even));
68 ASSERT_TRUE(partition.
checkBlockValidity(initBlock)) <<
"Block " << blockToString(initBlock) <<
" is not valid.";
75 EXPECT_TRUE(partition.
splitBlockByOrder(oddBlock, [](
auto const& a,
auto const& b) { return a % 3 < b % 3; }));
76 uint64_t seenSubBlocks = 0;
77 partition.
forEachSubBlock(oddBlock, [&partition, &seenSubBlocks](
auto const& block) {
78 ASSERT_TRUE(partition.
checkBlockValidity(block)) <<
"Block " << blockToString(block) <<
" is not valid.";
80 EXPECT_TRUE(equalBlocks(partition, {1, 7}, block));
82 }
else if (partition.
contains(block, 3)) {
83 EXPECT_TRUE(equalBlocks(partition, {3, 9}, block));
85 }
else if (partition.
contains(block, 5)) {
86 EXPECT_TRUE(equalBlocks(partition, {5}, block));
89 FAIL() <<
"Block " << blockToString(block) <<
" does not contain any expected elements.";
92 EXPECT_EQ(111ul, seenSubBlocks) <<
"Not all sub blocks have been seen.";
96 for (
auto i = 0ul;
i < 10; ++
i) {
97 EXPECT_EQ(partition.
contains(evenBlock, i), i % 2 == 0) <<
"Element " <<
i <<
" not in block " << blockToString(i % 2 == 0 ? evenBlock : oddBlock);
98 EXPECT_EQ(partition.
contains(oddBlock, i), i % 2 != 0) <<
"Element " <<
i <<
" in block " << blockToString(i % 2 != 0 ? oddBlock : evenBlock);
102 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5, 7, 9}, oddBlock));
105 auto [evenAndOddBlock, evenAndEvenBlock] = partition.
splitBlockByPredicate(evenBlock, [](
auto const& e) {
return e % 2 == 0; });
106 EXPECT_TRUE(evenAndOddBlock.empty());
107 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4, 6, 8}, evenAndEvenBlock));
110 auto [less10, geq10] = partition.
splitBlockByPredicate(evenBlock, [](
auto const& e) {
return e >= 10; });
111 EXPECT_TRUE(geq10.empty());
112 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4, 6, 8}, less10));
115 EXPECT_FALSE(partition.
splitBlockByOrder(evenBlock, [](
auto const& a,
auto const& b) { return a % 2 < b % 2; }));
119 blockSet.insert(evenBlock);
120 blockSet.insert(oddBlock);
121 EXPECT_EQ(blockSet.size(), 2);
122 blockSet.insert(evenAndEvenBlock);
123 EXPECT_EQ(blockSet.size(), 2);
125 EXPECT_EQ(blockSet.size(), 2);
126 EXPECT_EQ(blockSet.size(), 2);
128 EXPECT_EQ(blockSet.size(), 3);
131TEST(PartitionTest, SplitByRange) {
136 ASSERT_TRUE(partition.
checkBlockValidity(no)) <<
"Block " << blockToString(no) <<
" is not valid.";
137 ASSERT_TRUE(partition.
checkBlockValidity(yes)) <<
"Block " << blockToString(yes) <<
" is not valid.";
138 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4, 6, 8}, no));
139 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5, 7, 9}, yes));
144 auto [notInRange, inRange] = partition.
splitBlockByRange(no, std::vector<uint64_t>{0, 4, 4, 8, 1, 3});
145 ASSERT_TRUE(partition.
checkBlockValidity(notInRange)) <<
"Block " << blockToString(notInRange) <<
" is not valid.";
146 ASSERT_TRUE(partition.
checkBlockValidity(inRange)) <<
"Block " << blockToString(inRange) <<
" is not valid.";
147 EXPECT_TRUE(equalBlocks(partition, {2, 6}, notInRange));
148 EXPECT_TRUE(equalBlocks(partition, {0, 4, 8}, inRange));
152 auto [allOfYes, emptyBlock] = partition.
splitBlockByRange(yes, std::vector<uint64_t>{});
153 EXPECT_TRUE(emptyBlock.empty());
154 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5, 7, 9}, allOfYes));
158 auto [emptyBlock2, allOfYes2] = partition.
splitBlockByRange(yes, std::vector<uint64_t>{1, 3, 5, 7, 9});
159 EXPECT_TRUE(emptyBlock2.empty());
160 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5, 7, 9}, allOfYes2));
165TEST(PartitionTest, SplitByClustering) {
167 std::vector<int>
const value = {0, 5, 0, 5, 0, 9};
169 auto const condition = [&value](uint64_t
const a, uint64_t
const b) {
return value[a] != value[b]; };
173 partition.
forEachBlock([&partition](
auto const& block) {
174 ASSERT_TRUE(partition.
checkBlockValidity(block)) <<
"Block " << blockToString(block) <<
" is not valid.";
176 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4}, block));
177 }
else if (partition.
contains(block, 1)) {
178 EXPECT_TRUE(equalBlocks(partition, {1, 3}, block));
179 }
else if (partition.
contains(block, 5)) {
180 EXPECT_TRUE(equalBlocks(partition, {5}, block));
182 FAIL() <<
"Block " << blockToString(block) <<
" does not contain any expected elements.";
189 EXPECT_FALSE(trivialPartition.splitBlockByClustering(trivialPartition.getUniversalBlock(), [](uint64_t
const, uint64_t
const) { return false; }));
190 EXPECT_EQ(1ul, trivialPartition.getNumberOfBlocks());
198 std::vector<int>
const chainValue = {0, 4, 8};
200 auto const chainCondition = [&chainValue](uint64_t
const a, uint64_t
const b) {
return std::abs(chainValue[a] - chainValue[b]) > 5; };
201 EXPECT_TRUE(chainPartition.splitBlockByClustering(chainPartition.getUniversalBlock(), chainCondition));
202 EXPECT_EQ(2ul, chainPartition.getNumberOfBlocks());
203 EXPECT_TRUE(equalBlocks(chainPartition, {0, 1}, chainPartition.getBlockOfElement(0)));
204 EXPECT_TRUE(equalBlocks(chainPartition, {2}, chainPartition.getBlockOfElement(2)));
208TEST(PartitionTest, UniversalBlockAndSubBlockRelation) {
211 EXPECT_TRUE(equalBlocks(partition, {0, 1, 2, 3, 4, 5, 6, 7}, universal));
212 EXPECT_TRUE(partition.
isSubBlockOf(universal, universal));
215 auto [odd, even] = partition.
splitBlockByPredicate(universal, [](
auto const& e) {
return e % 2 == 0; });
219 EXPECT_TRUE(equalBlocks(partition, {0, 1, 2, 3, 4, 5, 6, 7}, stillUniversal));
222 EXPECT_TRUE(partition.
isSubBlockOf(odd, stillUniversal));
223 EXPECT_TRUE(partition.
isSubBlockOf(even, stillUniversal));
224 EXPECT_FALSE(partition.
isSubBlockOf(stillUniversal, odd));
233TEST(PartitionTest, SingletonBlockSplits) {
238 EXPECT_FALSE(partition.
splitBlockByOrder(block, [](
auto const& a,
auto const& b) { return a < b; }));
240 auto [emptyFalsePart, allTrue] = partition.
splitBlockByPredicate(block, [](
auto const&) {
return true; });
241 EXPECT_TRUE(emptyFalsePart.empty());
242 EXPECT_TRUE(equalBlocks(partition, {0}, allTrue));
244 auto [allFalse, emptyTruePart] = partition.
splitBlockByPredicate(block, [](
auto const&) {
return false; });
245 EXPECT_TRUE(emptyTruePart.empty());
246 EXPECT_TRUE(equalBlocks(partition, {0}, allFalse));
257 EXPECT_TRUE(equalBlocks(partition, {0}, isolated));
259 EXPECT_FALSE(partition.
splitBlockByOrder(isolated, [](
auto const& a,
auto const& b) { return a < b; }));
261 auto [notInRange, inRange] = partition.
splitBlockByRange(isolated, std::vector<uint64_t>{0});
262 EXPECT_TRUE(notInRange.empty());
263 EXPECT_TRUE(equalBlocks(partition, {0}, inRange));
265 auto [notInRange2, inRange2] = partition.
splitBlockByRange(isolated, std::vector<uint64_t>{});
266 EXPECT_TRUE(inRange2.empty());
267 EXPECT_TRUE(equalBlocks(partition, {0}, notInRange2));
273TEST(PartitionTest, NonSuperBlockSet) {
277 EXPECT_TRUE(nonSuperBlockSet.empty());
278 EXPECT_EQ(0ul, nonSuperBlockSet.size());
281 nonSuperBlockSet.insert(universalBlock);
282 EXPECT_FALSE(nonSuperBlockSet.empty());
283 EXPECT_EQ(1ul, nonSuperBlockSet.size());
284 EXPECT_TRUE(nonSuperBlockSet.contains(universalBlock));
288 EXPECT_EQ(1ul, nonSuperBlockSet.size());
290 auto poppedBlock = nonSuperBlockSet.pop();
291 EXPECT_TRUE(equalBlocks(partition, {0, 1, 2, 3, 4, 5}, poppedBlock));
292 EXPECT_TRUE(nonSuperBlockSet.empty());
294 auto [odd, even] = partition.
splitBlockByPredicate(poppedBlock, [](
auto const& e) {
return e % 2 == 0; });
295 nonSuperBlockSet.insert(odd);
296 nonSuperBlockSet.insert(even);
297 EXPECT_EQ(2ul, nonSuperBlockSet.size());
298 EXPECT_TRUE(nonSuperBlockSet.contains(odd));
299 EXPECT_TRUE(nonSuperBlockSet.contains(even));
302 auto b0 = nonSuperBlockSet.pop();
303 auto b1 = nonSuperBlockSet.pop();
304 EXPECT_TRUE(nonSuperBlockSet.empty());
306 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5}, b0));
307 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4}, b1));
309 EXPECT_TRUE(equalBlocks(partition, {0, 2, 4}, b0));
310 EXPECT_TRUE(equalBlocks(partition, {1, 3, 5}, b1));
312 EXPECT_FALSE(nonSuperBlockSet.contains(odd));
313 EXPECT_FALSE(nonSuperBlockSet.contains(even));
TEST(RegionConstraintCheckerTest, AffineConstraintHoldsThroughout)
Set of blocks that are no proper superblock.
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...
void forEachBlock(Func const &f) const
Applies the given function on each block in 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 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
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
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.
#define STORM_SILENT_EXPECT_THROW(statement, expected_exception)