52 cout << " Testing: " << name << "... " << flush; \
58 cout << "\033[32mPASS\033[0m\n"; \
64 cout << "\033[31mFAIL\033[0m (" << msg << ")\n"; \
67#define CHECK(cond, msg) \
69 if (!(cond)) { FAIL(msg); return; } \
72#define CHECK_EQ(a, b, msg) \
76 ss << msg << " (expected " << (b) << ", got " << (a) << ")"; \
85 chrono::high_resolution_clock::time_point
start;
90 auto end = chrono::high_resolution_clock::now();
91 return chrono::duration<double, milli>(end -
start).count();
113 for (
int i = 0; i < n; ++i)
116 for (
int i = 0; i < n - 1; ++i)
130 for (
int i = 0; i < n; ++i)
133 for (
int i = 0; i < n; ++i)
135 int next = (i + 1) % n;
148 for (
int i = 0; i < n; ++i)
151 for (
int i = 0; i < n; ++i)
152 for (
int j = i + 1; j < n; ++j)
167 for (
int i = 0; i <
k; ++i)
174 for (
int i = 0; i <
k; ++i)
175 for (
int j = i + 1; j <
k; ++j)
182 for (
int i = 0; i <
k; ++i)
183 for (
int j = i + 1; j <
k; ++j)
257 TEST(
"Karger-Stein: skipped (empty graph not supported by Karger)");
265 TEST(
"Karger-Stein: single edge (min-cut = 1)");
278 size_t best = numeric_limits<size_t>::max();
279 for (
int i = 0; i < 5; ++i)
281 size_t mc =
ks(g, S,
T, cut);
285 CHECK(
best <= 2,
"min-cut should be 1 or 2 (counting both directions)");
291 TEST(
"Karger-Stein: triangle (K3, min-cut = 2)");
307 size_t best = numeric_limits<size_t>::max();
308 for (
int i = 0; i < 10; ++i)
310 size_t mc =
ks(g, S,
T, cut);
314 CHECK(
best >= 2 &&
best <= 4,
"min-cut should be ~2 (accounting for bidirectional)");
320 TEST(
"Karger-Stein: barbell graph (min-cut = 1)");
330 size_t best = numeric_limits<size_t>::max();
331 for (
int i = 0; i < 20; ++i)
333 size_t mc =
ks(g, S,
T, cut);
337 CHECK(
best <= 2,
"min-cut should be ~1-2 (bridge)");
343 TEST(
"Karger-Stein: path graph (min-cut = 1)");
352 size_t best = numeric_limits<size_t>::max();
353 for (
int i = 0; i < 10; ++i)
355 size_t mc =
ks(g, S,
T, cut);
359 CHECK(
best <= 2,
"min-cut should be ~1-2");
365 TEST(
"Karger-Stein: cycle graph (min-cut = 2)");
374 size_t best = numeric_limits<size_t>::max();
375 for (
int i = 0; i < 20; ++i)
377 size_t mc =
ks(g, S,
T, cut);
381 CHECK(
best >= 2 &&
best <= 4,
"min-cut should be ~2 for cycle");
387 TEST(
"Karger-Stein: two clusters with 3 bridges (min-cut = 3)");
396 size_t best = numeric_limits<size_t>::max();
397 for (
int i = 0; i < 30; ++i)
399 size_t mc =
ks(g, S,
T, cut);
403 CHECK(
best >= 3 &&
best <= 6,
"min-cut should be ~3-6 (3 bridges, bidirectional)");
409 TEST(
"Karger-Stein: find_with_iterations method");
418 size_t mc =
ks(g, S,
T, cut, 20);
420 CHECK(
mc <= 2,
"min-cut should be ~1-2 with sufficient iterations");
422 CHECK(!
T.is_empty(),
"partition T non-empty");
428 TEST(
"Karger-Stein: seed reproducibility");
452 TEST(
"Stoer-Wagner: empty graph (2 nodes, no edges)");
471 TEST(
"Stoer-Wagner: single edge weight 5");
491 TEST(
"Stoer-Wagner: weighted triangle");
520 TEST(
"Stoer-Wagner: weighted chain A-10-B-1-C-10-D");
531 CHECK(
min_cut <= 2,
"min-cut should be ~1 (the weak middle edge)");
537 TEST(
"Stoer-Wagner: complete K4 (all weights 1)");
567 TEST(
"Stoer-Wagner: two clusters with weak bridge");
590 CHECK(
min_cut <= 2,
"min-cut should be ~1 (the weak bridge)");
596 TEST(
"Stoer-Wagner: min_cut_weight (no partition)");
610 TEST(
"Stoer-Wagner: Unit_Weight functor (unweighted)");
615 auto n0 = g.insert_node(0);
616 auto n1 = g.insert_node(1);
617 auto n2 = g.insert_node(2);
618 auto n3 = g.insert_node(3);
621 g.insert_arc(n0, n1, 999);
622 g.insert_arc(n1, n0, 999);
623 g.insert_arc(n1, n2, 999);
624 g.insert_arc(n2, n1, 999);
625 g.insert_arc(n2, n3, 999);
626 g.insert_arc(n3, n2, 999);
634 CHECK(
min_cut <= 2,
"min-cut should be 1-2 (counting edges, not weights)");
644 TEST(
"Cross-comparison: both algorithms on same graph");
652 for (
int i = 0; i < 4; ++i)
659 for (
int i = 0; i < 4; ++i)
660 for (
int j = i + 1; j < 4; ++j)
667 for (
int i = 0; i < 4; ++i)
668 for (
int j = i + 1; j < 4; ++j)
685 size_t ks_best = numeric_limits<size_t>::max();
686 for (
int i = 0; i < 30; ++i)
710 TEST(
"Performance: Karger-Stein on 50-node graph");
716 for (
int i = 0; i <
N; ++i)
720 for (
int i = 0; i <
N - 1; ++i)
727 for (
int i = 0; i <
N; i += 3)
728 for (
int j = i + 5; j <
N; j += 5)
739 size_t mc =
ks(g, S,
T, cut, 5);
740 double elapsed =
timer.elapsed_ms();
742 CHECK(elapsed < 10000,
"should complete in < 10 seconds");
743 CHECK(
mc >= 1,
"should find a cut");
749 TEST(
"Performance: Stoer-Wagner on 50-node graph");
755 for (
int i = 0; i <
N; ++i)
759 for (
int i = 0; i <
N - 1; ++i)
766 for (
int i = 0; i <
N; i += 3)
767 for (
int j = i + 5; j <
N; j += 5)
778 int mc =
sw(g, S,
T, cut);
779 double elapsed =
timer.elapsed_ms();
781 CHECK(elapsed < 5000,
"should complete in < 5 seconds");
782 CHECK(
mc >= 0,
"should find a cut");
792 cout <<
"╔══════════════════════════════════════════════════════════════╗\n";
793 cout <<
"║ Min-Cut Algorithms Test Suite ║\n";
794 cout <<
"║ Testing Karger-Stein and Stoer-Wagner ║\n";
795 cout <<
"╚══════════════════════════════════════════════════════════════╝\n\n";
797 cout <<
"=== Karger-Stein Tests ===\n";
808 cout <<
"\n=== Stoer-Wagner Tests ===\n";
818 cout <<
"\n=== Cross-Algorithm Tests ===\n";
821 cout <<
"\n=== Performance Tests ===\n";
826 cout <<
"══════════════════════════════════════════════════════════════\n";
831 cout <<
"══════════════════════════════════════════════════════════════\n";
Karger's randomized min-cut algorithm.
Stoer-Wagner deterministic min-cut algorithm.
Dynamic singly linked list with functional programming support.
constexpr bool is_empty() const noexcept
Return true if list is empty.
size_t size() const noexcept
Count the number of elements of the list.
Karger's randomized minimum cut algorithm.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Stoer-Wagner deterministic minimum cut algorithm.
double elapsed_ms() const
chrono::high_resolution_clock::time_point start
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
DynArray< Graph::Node * > nodes
void test_ks_empty_graph()
void build_two_clusters(UnweightedGraph &g, int cluster_size, int bridge_count)
Build two clusters connected by k edges Min-cut: k.
void test_sw_min_cut_weight_only()
#define CHECK_EQ(a, b, msg)
void test_performance_sw()
void build_complete_graph(UnweightedGraph &g, int n)
Build a complete graph Kn Min-cut: n-1 (isolate any single vertex)
void test_sw_chain_weighted()
void test_ks_find_with_iterations()
void build_cycle_graph(UnweightedGraph &g, int n)
Build a cycle graph: 0 - 1 - 2 - ... - (n-1) - 0 Min-cut: 2 (need to cut two edges to disconnect)
void test_ks_two_clusters()
void test_ks_seed_reproducibility()
void test_performance_ks()
void test_sw_single_edge()
void test_sw_two_heavy_clusters()
void test_cross_comparison()
void build_barbell_graph(UnweightedGraph &g, int k)
Build a barbell graph: two K_k cliques connected by a single edge Min-cut: 1 (the bridge between cliq...
void build_path_graph(UnweightedGraph &g, int n)
Build a path graph: 0 - 1 - 2 - ... - (n-1) Min-cut: 1 (any single edge)
void test_ks_single_edge()
void test_sw_complete_k4()
void test_sw_empty_graph()
void test_sw_unit_weight()
void build_weighted_chain(WeightedGraph &g, int w1, int w2, int w3)
Build a weighted graph with known min-cut Structure: A-B-C-D where weights determine the cut.
void test_sw_triangle_weighted()
Main namespace for Aleph-w library functions.
std::decay_t< typename HeadC::Item_Type > T
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
void next()
Advance all underlying iterators (bounds-checked).
Net::Flow_Type min_cut(Net &net, DynSetTree< typename Net::Node * > &vs, DynSetTree< typename Net::Node * > &vt, DynList< typename Net::Arc * > &cuts, DynList< typename Net::Arc * > &cutt)
Compute max flow and the corresponding minimum cut.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.