Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
hamiltonian_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
41#include <gtest/gtest.h>
42#include <hamiltonian.H>
43#include <tpl_graph.H>
44
45using namespace Aleph;
46
47// =============================================================================
48// Test Fixtures
49// =============================================================================
50
51class HamiltonianUndirectedTest : public ::testing::Test
52{
53protected:
56 using Arc = Graph::Arc;
57
59
60 Node* add_node(int val)
61 {
62 return g.insert_node(val);
63 }
64
65 Arc* add_edge(Node* n1, Node* n2)
66 {
67 return g.insert_arc(n1, n2, 1);
68 }
69
70 // Build complete graph Kn
72 {
73 std::vector<Node*> nodes;
74 for (int i = 0; i < n; ++i)
75 nodes.push_back(add_node(i));
76
77 for (int i = 0; i < n; ++i)
78 for (int j = i + 1; j < n; ++j)
79 add_edge(nodes[i], nodes[j]);
80 }
81};
82
83class HamiltonianDigraphTest : public ::testing::Test
84{
85protected:
89
91
92 Node* add_node(int val)
93 {
94 return g.insert_node(val);
95 }
96
97 Arc* add_arc(Node* src, Node* tgt)
98 {
99 return g.insert_arc(src, tgt, 1);
100 }
101};
102
103// =============================================================================
104// Undirected Graph Tests - Ore's Theorem
105// =============================================================================
106
108{
109 // K3: Each vertex has degree 2, n=3
110 // For non-adjacent pairs (none exist), condition trivially satisfied
112
114 EXPECT_TRUE(test(g));
115}
116
118{
119 // K4: Each vertex has degree 3, n=4
120 // No non-adjacent pairs, so Ore's condition satisfied
122
124 EXPECT_TRUE(test(g));
125}
126
128{
129 // K5: Each vertex has degree 4, n=5
131
133 EXPECT_TRUE(test(g));
134}
135
144
146{
147 // Cycle C5: degrees are all 2, n=5
148 // Non-adjacent pairs: deg sum = 4 < 5, fails Ore
149 auto n1 = add_node(1);
150 auto n2 = add_node(2);
151 auto n3 = add_node(3);
152 auto n4 = add_node(4);
153 auto n5 = add_node(5);
154
155 add_edge(n1, n2);
156 add_edge(n2, n3);
157 add_edge(n3, n4);
158 add_edge(n4, n5);
159 add_edge(n5, n1);
160
162 // Note: Graph IS Hamiltonian, but Ore's condition is NOT satisfied
163 // This is expected - Ore gives sufficient but not necessary condition
164 EXPECT_FALSE(test(g));
165}
166
168{
169 // Path P4: 1-2-3-4
170 // degrees: 1,2,2,1
171 // Non-adjacent (1,3): 1+2=3 < 4, fails
172 auto n1 = add_node(1);
173 auto n2 = add_node(2);
174 auto n3 = add_node(3);
175 auto n4 = add_node(4);
176
177 add_edge(n1, n2);
178 add_edge(n2, n3);
179 add_edge(n3, n4);
180
182 EXPECT_FALSE(test(g));
183}
184
186{
187 // Graph where each vertex has degree ≥ n/2
188 // This satisfies Dirac's condition (stronger than Ore)
189 // n=4, each vertex has degree 2 (= n/2)
190 auto n1 = add_node(1);
191 auto n2 = add_node(2);
192 auto n3 = add_node(3);
193 auto n4 = add_node(4);
194
195 // Make it "almost complete" - missing one edge
196 add_edge(n1, n2);
197 add_edge(n1, n3);
198 add_edge(n2, n3);
199 add_edge(n2, n4);
200 add_edge(n3, n4);
201 // Missing: n1-n4
202
204 // n1 and n4 non-adjacent: deg(n1)=2, deg(n4)=2, sum=4 ≥ n=4 ✓
205 EXPECT_TRUE(test(g));
206}
207
209{
210 // Star graph: center connected to all, leaves not connected
211 // Center degree = 4, leaf degree = 1
212 // Non-adjacent leaves: 1+1=2 < 5, fails
213 auto center = add_node(0);
214 auto n1 = add_node(1);
215 auto n2 = add_node(2);
216 auto n3 = add_node(3);
217 auto n4 = add_node(4);
218
219 add_edge(center, n1);
220 add_edge(center, n2);
221 add_edge(center, n3);
222 add_edge(center, n4);
223
225 EXPECT_FALSE(test(g));
226}
227
229{
230 // A non-Hamiltonian graph that also fails Ore
231 // Simple 5-vertex graph with low connectivity
232 auto n1 = add_node(1);
233 auto n2 = add_node(2);
234 auto n3 = add_node(3);
235 auto n4 = add_node(4);
236 add_node(5);
237
238 // Pentagon with some missing edges
239 add_edge(n1, n2);
240 add_edge(n2, n3);
241 add_edge(n3, n4);
242
244 EXPECT_FALSE(test(g));
245}
246
248{
249 // K5 minus one edge
250 auto n1 = add_node(1);
251 auto n2 = add_node(2);
252 auto n3 = add_node(3);
253 auto n4 = add_node(4);
254 auto n5 = add_node(5);
255
256 // All edges except n1-n2
257 add_edge(n1, n3); add_edge(n1, n4); add_edge(n1, n5);
258 add_edge(n2, n3); add_edge(n2, n4); add_edge(n2, n5);
259 add_edge(n3, n4); add_edge(n3, n5);
260 add_edge(n4, n5);
261
263 // n1 and n2 non-adjacent: deg(n1)=3, deg(n2)=3, sum=6 ≥ n=5 ✓
264 EXPECT_TRUE(test(g));
265}
266
268{
269 // Complete bipartite K3,3: IS Hamiltonian
270 // Each vertex has degree 3, n=6
271 // Non-adjacent pairs within same partition: 3+3=6 ≥ 6 ✓
272 auto a1 = add_node(1);
273 auto a2 = add_node(2);
274 auto a3 = add_node(3);
275 auto b1 = add_node(4);
276 auto b2 = add_node(5);
277 auto b3 = add_node(6);
278
279 // Connect all a's to all b's
280 add_edge(a1, b1); add_edge(a1, b2); add_edge(a1, b3);
281 add_edge(a2, b1); add_edge(a2, b2); add_edge(a2, b3);
282 add_edge(a3, b1); add_edge(a3, b2); add_edge(a3, b3);
283
285 // Non-adjacent in same partition: 3+3=6 ≥ 6 ✓
286 EXPECT_TRUE(test(g));
287}
288
289// =============================================================================
290// Directed Graph Tests
291// =============================================================================
292
294{
295 // Complete directed graph: every pair has arcs in both directions
296 auto n1 = add_node(1);
297 auto n2 = add_node(2);
298 auto n3 = add_node(3);
299
300 add_arc(n1, n2); add_arc(n2, n1);
301 add_arc(n1, n3); add_arc(n3, n1);
302 add_arc(n2, n3); add_arc(n3, n2);
303
305 // out-deg + in-deg = 4 for each, n=3
306 // For digraph Ore: out(u) + in(v) ≥ n when no arc u→v
307 EXPECT_TRUE(test(g));
308}
309
311{
312 // Simple directed cycle 1→2→3→1
313 auto n1 = add_node(1);
314 auto n2 = add_node(2);
315 auto n3 = add_node(3);
316
317 add_arc(n1, n2);
318 add_arc(n2, n3);
319 add_arc(n3, n1);
320
322 // out=1, in=1 for each
323 // For pair without arc: out(u) + in(v) = 1+1 = 2 < n=3
324 EXPECT_FALSE(test(g));
325}
326
328{
329 // Path 1→2→3
330 auto n1 = add_node(1);
331 auto n2 = add_node(2);
332 auto n3 = add_node(3);
333
334 add_arc(n1, n2);
335 add_arc(n2, n3);
336
338 EXPECT_FALSE(test(g));
339}
340
342{
343 // Tournament: directed complete graph (one arc between each pair)
344 // 1→2, 1→3, 2→3
345 auto n1 = add_node(1);
346 auto n2 = add_node(2);
347 auto n3 = add_node(3);
348
349 add_arc(n1, n2);
350 add_arc(n1, n3);
351 add_arc(n2, n3);
352
354 // This tournament has Hamiltonian path but may not satisfy Ore
355 // n1: out=2, in=0; n2: out=1, in=1; n3: out=0, in=2
356 // Pair without arc 2→1: out(n2)+in(n1) = 1+0 = 1 < 3
357 EXPECT_FALSE(test(g));
358}
359
360// =============================================================================
361// Edge Cases
362// =============================================================================
363
365{
366 // n=2: Ore's theorem requires n >= 3
367 auto n1 = add_node(1);
368 auto n2 = add_node(2);
369 add_edge(n1, n2);
370
372 // Ore's theorem doesn't apply for n < 3
373 EXPECT_FALSE(test(g));
374}
375
377{
378 // n=2, disconnected: fails Ore (no edges)
379 add_node(1);
380 add_node(2);
381
383 // deg(n1)=deg(n2)=0, 0+0=0 < 2
384 EXPECT_FALSE(test(g));
385}
386
388{
389 // Performance test with larger graph
391
393 EXPECT_TRUE(test(g));
394}
395
396// =============================================================================
397// Tests for Dirac's Condition
398// =============================================================================
399
401{
402 // K4: each vertex has degree 3, n=4, need deg >= 2
403 // 3 >= 2 ✓
405
407 EXPECT_TRUE(test(g));
408 EXPECT_EQ(test.min_required_degree(g), 2);
409}
410
412{
413 // K5: each vertex has degree 4, n=5, need deg >= 3
414 // 4 >= 3 ✓
416
418 EXPECT_TRUE(test(g));
419 EXPECT_EQ(test.min_required_degree(g), 3);
420}
421
423{
424 // Cycle C5: each vertex has degree 2, n=5, need deg >= 3
425 // 2 < 3 ✗
426 const int n = 5;
427 std::vector<Graph::Node*> nodes;
428 for (int i = 0; i < n; ++i)
429 nodes.push_back(add_node(i));
430
431 for (int i = 0; i < n; ++i)
432 add_edge(nodes[i], nodes[(i+1) % n]);
433
435 EXPECT_FALSE(test(g));
436
437 auto [min_deg, min_node] = test.find_min_degree_vertex(g);
438 EXPECT_EQ(min_deg, 2);
439}
440
442{
443 // Graph where Ore passes but Dirac fails
444 // Example: Path P4 with some extra edges
445 // n=4, Ore needs deg(u)+deg(v) >= 4 for non-adjacent
446 // Dirac needs deg(v) >= 2 for all
447
448 auto n1 = add_node(1);
449 auto n2 = add_node(2);
450 auto n3 = add_node(3);
451 auto n4 = add_node(4);
452
453 // Build a cycle (satisfies Dirac for n=4, need deg >= 2)
454 add_edge(n1, n2);
455 add_edge(n2, n3);
456 add_edge(n3, n4);
457 add_edge(n4, n1);
458
461
462 // Both should pass for a cycle of length 4
463 EXPECT_TRUE(dirac(g));
464 EXPECT_TRUE(ore(g));
465}
466
468{
469 // n=2: Dirac requires n >= 3
470 auto n1 = add_node(1);
471 auto n2 = add_node(2);
472 add_edge(n1, n2);
473
475 EXPECT_FALSE(test(g));
476}
477
479{
480 // If Dirac passes, Ore should also pass
481 // Test with K6
483
486
487 // Dirac: deg = 5 >= 3 (n/2 = 3) ✓
488 EXPECT_TRUE(dirac(g));
489 // Ore should also pass (it's less restrictive)
490 EXPECT_TRUE(ore(g));
491}
492
493// Dirac for Digraphs
495{
496 // Complete digraph K4 (tournament)
497 // Each vertex: in=out=3, n=4, need >= 2
498 const int n = 4;
499 std::vector<Digraph::Node*> nodes;
500 for (int i = 0; i < n; ++i)
501 nodes.push_back(add_node(i));
502
503 // Add all directed edges (both directions)
504 for (int i = 0; i < n; ++i)
505 for (int j = 0; j < n; ++j)
506 if (i != j)
507 add_arc(nodes[i], nodes[j]);
508
510 EXPECT_TRUE(test(g));
511}
512
513// =============================================================================
514// Main
515// =============================================================================
516
517int main(int argc, char **argv)
518{
519 ::testing::InitGoogleTest(&argc, argv);
520 return RUN_ALL_TESTS();
521}
int main()
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
typename BaseGraph::Arc Arc
Definition graph-dry.H:3852
typename BaseGraph::Node Node
Definition graph-dry.H:3851
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Graph_Arc< int > Arc
The node class type.
Definition tpl_graph.H:433
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Tests Dirac's sufficient condition for Hamiltonian graphs.
Tests Ore's sufficient condition for Hamiltonian graphs.
Arc * add_arc(Node *src, Node *tgt)
Arc * add_edge(Node *n1, Node *n2)
void add_edge(GT &g, const string &src, const string &tgt, int weight=1)
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Hamiltonian sufficiency testing for graphs.
void build_complete_graph(UGraph &g, size_t n)
TEST_F(HamiltonianUndirectedTest, CompleteGraphK3)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
TestDigraph::Arc * add_arc(TestDigraph &g, TestDigraph::Node *src, TestDigraph::Node *tgt, int value=0)
TestDigraph::Node * add_node(TestDigraph &g, int value)
void test(unsigned long n, gsl_rng *r)
Generic graph and digraph implementations.