20#include <boost/test/unit_test.hpp>
42bool edgeOrder(
const TEST_EDGE& aLhs,
const TEST_EDGE& aRhs )
44 return std::tie( aLhs.weight, aLhs.u, aLhs.v ) < std::tie( aRhs.weight, aRhs.u, aRhs.v );
48std::pair<size_t, size_t> edgeEnds(
const TEST_EDGE& aEdge )
50 return { aEdge.u, aEdge.v };
59std::vector<TEST_EDGE> referenceKruskal( std::vector<TEST_EDGE> aEdges,
size_t aNodes,
60 const std::vector<std::pair<size_t, size_t>>& aSeeds )
64 for(
const auto& [a, b] : aSeeds )
67 std::sort( aEdges.begin(), aEdges.end(), edgeOrder );
69 std::vector<TEST_EDGE> tree;
71 for(
const TEST_EDGE& edge : aEdges )
73 if( forest.Unite( edge.u, edge.v ) )
74 tree.push_back( edge );
81std::vector<TEST_EDGE> filterKruskal( std::vector<TEST_EDGE> aEdges,
size_t aNodes,
82 const std::vector<std::pair<size_t, size_t>>& aSeeds,
83 size_t& aReturnedCount )
87 for(
const auto& [a, b] : aSeeds )
90 std::vector<TEST_EDGE> tree;
93 aEdges, forest, edgeOrder, edgeEnds,
94 [&](
const TEST_EDGE& aEdge ) { tree.push_back( aEdge ); } );
100int64_t totalWeight(
const std::vector<TEST_EDGE>& aTree )
104 for(
const TEST_EDGE& edge : aTree )
105 total += edge.weight;
116void checkAgainstReference(
const std::vector<TEST_EDGE>& aEdges,
size_t aNodes,
117 const std::vector<std::pair<size_t, size_t>>& aSeeds = {} )
119 size_t reportedCount = 0;
120 std::vector<TEST_EDGE> got = filterKruskal( aEdges, aNodes, aSeeds, reportedCount );
121 std::vector<TEST_EDGE> want = referenceKruskal( aEdges, aNodes, aSeeds );
123 BOOST_REQUIRE_EQUAL( reportedCount, got.size() );
124 BOOST_REQUIRE_EQUAL( got.size(), want.size() );
125 BOOST_REQUIRE_EQUAL( totalWeight( got ), totalWeight( want ) );
129 for(
size_t ii = 1; ii < got.size(); ++ii )
132 std::vector<TEST_EDGE> sortedGot = got;
133 std::vector<TEST_EDGE> sortedWant = want;
134 std::sort( sortedGot.begin(), sortedGot.end(), edgeOrder );
135 std::sort( sortedWant.begin(), sortedWant.end(), edgeOrder );
137 for(
size_t ii = 0; ii < sortedGot.size(); ++ii )
139 BOOST_REQUIRE_EQUAL( sortedGot[ii].u, sortedWant[ii].u );
140 BOOST_REQUIRE_EQUAL( sortedGot[ii].v, sortedWant[ii].v );
141 BOOST_REQUIRE_EQUAL( sortedGot[ii].weight, sortedWant[ii].weight );
146std::vector<TEST_EDGE> randomEdges( std::mt19937& aRng,
size_t aNodes,
size_t aCount,
147 int64_t aWeightRange )
149 std::vector<TEST_EDGE> edges;
150 edges.reserve( aCount );
152 for(
size_t ii = 0; ii < aCount; ++ii )
154 edges.push_back( { aRng() % aNodes, aRng() % aNodes,
155 (int64_t) ( aRng() % (uint32_t) aWeightRange ) } );
173 std::mt19937
rng( 555 );
175 for(
int trial = 0; trial < 60; ++trial )
177 const size_t nodes = 2 +
rng() % 2000;
178 const size_t count =
rng() % ( 5 * nodes );
180 checkAgainstReference( randomEdges(
rng, nodes, count, 100000 ), nodes );
191 std::mt19937
rng( 12 );
193 for(
int trial = 0; trial < 8; ++trial )
195 const size_t nodes = 500 +
rng() % 2000;
196 std::vector<TEST_EDGE> edges = randomEdges(
rng, nodes, 5 * nodes, 100000 );
198 for( TEST_EDGE& edge : edges )
201 checkAgainstReference( edges, nodes );
208 std::mt19937
rng( 606 );
210 for(
int trial = 0; trial < 8; ++trial )
212 const size_t nodes = 1000 +
rng() % 1500;
214 checkAgainstReference( randomEdges(
rng, nodes, 6 * nodes, 2 ), nodes );
225 std::mt19937
rng( 808 );
227 const size_t nodes = 4000;
228 const size_t islands = 8;
229 const size_t islandSize = nodes / islands;
231 std::vector<TEST_EDGE> edges;
233 for(
size_t ii = 0; ii < 20000; ++ii )
235 size_t island =
rng() % islands;
236 edges.push_back( { island * islandSize +
rng() % islandSize,
237 island * islandSize +
rng() % islandSize,
238 (int64_t) (
rng() % 1000 ) } );
241 checkAgainstReference( edges, nodes );
251 std::mt19937
rng( 909 );
253 const size_t nodes = 3000;
255 std::vector<std::pair<size_t, size_t>> seeds;
257 for(
size_t ii = 0; ii < 2000; ++ii )
258 seeds.emplace_back(
rng() % nodes,
rng() % nodes );
260 std::vector<TEST_EDGE> edges = randomEdges(
rng, nodes, 15000, 5000 );
262 for( TEST_EDGE& edge : edges )
265 checkAgainstReference( edges, nodes, seeds );
275 std::mt19937
rng( 246 );
277 const size_t nodes = 5000;
278 std::vector<TEST_EDGE> edges = randomEdges(
rng, nodes, 25000, 50 );
281 std::vector<TEST_EDGE> first = filterKruskal( edges, nodes, {}, count );
283 for(
int repeat = 0; repeat < 4; ++repeat )
285 std::vector<TEST_EDGE> again = filterKruskal( edges, nodes, {}, count );
287 BOOST_REQUIRE_EQUAL( again.size(), first.size() );
289 for(
size_t ii = 0; ii < again.size(); ++ii )
291 BOOST_REQUIRE_EQUAL( again[ii].u, first[ii].u );
292 BOOST_REQUIRE_EQUAL( again[ii].v, first[ii].v );
293 BOOST_REQUIRE_EQUAL( again[ii].weight, first[ii].weight );
308 [](
const TEST_EDGE& aEdge )
310 size_t low = std::min( aEdge.u, aEdge.v );
311 size_t high = std::max( aEdge.u, aEdge.v );
313 return std::tuple<int64_t, size_t, size_t>( aEdge.weight, low, high );
316 auto canonicalOrder =
317 [&canonical](
const TEST_EDGE& aLhs,
const TEST_EDGE& aRhs )
319 return canonical( aLhs ) < canonical( aRhs );
322 std::mt19937
rng( 1357 );
324 const size_t nodes = 4000;
325 std::vector<TEST_EDGE> edges = randomEdges(
rng, nodes, 20000, 40 );
328 [&]( std::vector<TEST_EDGE> aInput )
331 std::vector<TEST_EDGE> tree;
334 aInput, forest, canonicalOrder, edgeEnds,
335 [&](
const TEST_EDGE& aEdge ) { tree.push_back( aEdge ); } );
337 std::vector<std::tuple<int64_t, size_t, size_t>> keys;
339 for(
const TEST_EDGE& edge : tree )
340 keys.push_back( canonical( edge ) );
342 std::sort( keys.begin(), keys.end() );
347 std::vector<std::tuple<int64_t, size_t, size_t>>
expected = select( edges );
349 for(
int trial = 0; trial < 8; ++trial )
351 std::vector<TEST_EDGE> permuted = edges;
353 std::shuffle( permuted.begin(), permuted.end(),
rng );
355 for( TEST_EDGE& edge : permuted )
358 std::swap( edge.u, edge.v );
368 checkAgainstReference( {}, 1 );
369 checkAgainstReference( { { 0, 1, 5 } }, 2 );
372 checkAgainstReference( { { 0, 0, 1 }, { 1, 1, 2 }, { 0, 1, 3 } }, 2 );
376 std::vector<TEST_EDGE> tree =
377 filterKruskal( { { 0, 1, 9 }, { 0, 1, 2 }, { 0, 1, 7 } }, 2, {}, count );
Lock-free disjoint-set over a dense range of indices.
static thread_local boost::mt19937 rng
size_t FilterKruskal(std::span< EDGE > aEdges, KI_UNION_FIND &aForest, LESS aLess, ENDPOINTS aEndpoints, EMIT aEmit)
Build a minimum spanning forest over aEdges.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(MatchesPlainKruskal)
Sizes are chosen to straddle KRUSKAL_THRESHOLD so both the recursive partitioning path and the direct...
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
VECTOR3I expected(15, 30, 45)
BOOST_CHECK_EQUAL(result, "25.4")