Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
blossom_example.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
52# include <algorithm>
53# include <fstream>
54# include <iomanip>
55# include <iostream>
56# include <string>
57# include <utility>
58
59# include <tpl_array.H>
60# include <tpl_dynSetTree.H>
61# include <Blossom.H>
62# include <tpl_graph.H>
63# include <tpl_sgraph.H>
64# include <tpl_agraph.H>
65
66using namespace std;
67using namespace Aleph;
68
69namespace
70{
71 struct Node_Pos
72 {
73 double x = 0;
74 double y = 0;
75 string label;
76 };
77
78 struct Scenario
79 {
80 string slug;
81 string title;
84 };
85
97 template <class GT>
98 GT build_graph(const Scenario & s)
99 {
100 GT g;
102 nodes.reserve(s.nodes.size());
103
104 for (size_t i = 0; i < s.nodes.size(); ++i)
105 nodes.append(g.insert_node(static_cast<int>(i)));
106
107 for (const auto & [u, v] : s.edges)
108 {
109 ah_range_error_if(u >= s.nodes.size() or v >= s.nodes.size())
110 << "Edge endpoint out of range";
111 g.insert_arc(nodes[u], nodes[v], 1);
112 }
113
114 return g;
115 }
116
129 template <class GT>
131 const GT & g,
133 {
135
136 for (auto it = matching.get_it(); it.has_curr(); it.next_ne())
137 {
138 auto * arc = it.get_curr();
139 size_t u = static_cast<size_t>(g.get_src_node(arc)->get_info());
140 size_t v = static_cast<size_t>(g.get_tgt_node(arc)->get_info());
141 if (u > v)
142 swap(u, v);
143 seen.insert(make_pair(u, v));
144 }
145
147 for (const auto & p : seen)
148 result.append(p);
149
150 return result;
151 }
152
161 string format_pairs(const Array<pair<size_t, size_t>> & pairs)
162 {
163 if (pairs.is_empty())
164 return "(empty)";
165
166 string out;
167 for (size_t i = 0; i < pairs.size(); ++i)
168 {
169 const auto & [u, v] = pairs[i];
170 out += "(" + to_string(u) + "," + to_string(v) + ")";
171 if (i + 1 < pairs.size())
172 out += " ";
173 }
174 return out;
175 }
176
190 void write_tikz(const Scenario & s,
192 const string & file_path)
193 {
195 for (auto [u, v] : matching_pairs)
196 {
197 if (u > v)
198 swap(u, v);
199 matched_set.insert(make_pair(u, v));
200 }
201
202 ofstream out(file_path);
203 if (not out)
204 {
205 cerr << "Cannot write file: " << file_path << endl;
206 return;
207 }
208
209 out << "\\documentclass[tikz,border=10pt]{standalone}\n";
210 out << "\\usepackage{tikz}\n";
211 out << "\\usetikzlibrary{arrows.meta}\n";
212 out << "\\begin{document}\n";
213 out << "\\begin{tikzpicture}[x=1cm,y=1cm]\n";
214
215 out << " \\fill[blue!2] (-4.2,-3.2) rectangle (4.2,3.2);\n";
216 out << " \\node[font=\\bfseries\\large] at (0,2.95) {"
217 << s.title << "};\n";
218
219 out << " \\tikzset{"
220 << "edge/.style={line width=0.9pt, draw=black!65},"
221 << "match/.style={line width=2.6pt, draw=orange!90!black},"
222 << "vertex/.style={circle, draw=black!70, fill=white, minimum size=9mm, inner sep=1pt, font=\\small\\bfseries}"
223 << "}\n";
224
225 for (size_t i = 0; i < s.nodes.size(); ++i)
226 {
227 const auto & node = s.nodes[i];
228 out << " \\node[vertex] (n" << i << ") at ("
229 << fixed << setprecision(2) << node.x << "," << node.y << ") {"
230 << node.label << "};\n";
231 }
232
233 for (const auto & [u, v] : s.edges)
234 {
235 ah_range_error_if(u >= s.nodes.size() or v >= s.nodes.size())
236 << "Edge endpoint out of range";
237
238 size_t a = u;
239 size_t b = v;
240 if (a > b)
241 swap(a, b);
242
243 if (matched_set.search(make_pair(a, b)) != nullptr)
244 continue;
245
246 out << " \\draw[edge] (n" << u << ") -- (n" << v << ");\n";
247 }
248
249 for (auto [u, v] : matching_pairs)
250 out << " \\draw[match] (n" << u << ") -- (n" << v << ");\n";
251
252 out << " \\node[font=\\small] at (0,-2.95) {matching size = "
253 << matching_pairs.size() << "};\n";
254
255 out << "\\end{tikzpicture}\n";
256 out << "\\end{document}\n";
257 }
258
265 template <class GT>
267 {
268 GT g = build_graph<GT>(s);
270 const size_t cardinality = blossom_maximum_cardinality_matching<GT>(g, matching);
271 return std::make_pair(cardinality, extract_matching_pairs(g, matching));
272 }
273
289 template <class GT>
290 void print_backend_result(const string & backend_name,
291 const Scenario & s,
292 size_t & cardinality_ref,
294 bool & is_first)
295 {
296 auto [cardinality, pairs] = solve_case<GT>(s);
297
298 if (is_first)
299 {
300 cardinality_ref = cardinality;
301 pairs_ref = pairs;
302 is_first = false;
303 }
304
305 cout << " " << backend_name << " -> size " << cardinality
306 << " | " << format_pairs(pairs) << "\n";
307
308 if (cardinality != cardinality_ref)
309 cerr << " Warning: cardinality mismatch across backends\n";
310 }
311
323 void run_scenario(const Scenario & s)
324 {
325 cout << "\n" << s.title << "\n";
326 cout << string(s.title.size(), '-') << "\n";
327
328 size_t cardinality = 0;
330 bool first = true;
331
333 "List_Graph", s, cardinality, canonical_pairs, first);
334
336 "List_SGraph", s, cardinality, canonical_pairs, first);
337
339 "Array_Graph", s, cardinality, canonical_pairs, first);
340
341 const string tex_path = "/tmp/blossom_" + s.slug + ".tex";
343
344 cout << " TikZ export: " << tex_path << "\n";
345 }
346}
347
357int main()
358{
359 const Scenario pentagon_stems{
360 .slug = "pentagon_stems",
361 .title = "Blossom demo: odd cycle + stems",
362 .nodes = {
363 {-1.90, 1.10, "0"},
364 { 0.00, 2.20, "1"},
365 { 1.90, 1.10, "2"},
366 { 1.30, -1.10, "3"},
367 {-1.30, -1.10, "4"},
368 {-3.10, 2.35, "5"},
369 { 3.10, 2.35, "6"},
370 { 2.70, -2.05, "7"}
371 },
372 .edges = {
373 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0},
374 {1, 5}, {2, 6}, {3, 7}
375 }
376 };
377
378 const Scenario double_flower{
379 .slug = "double_flower",
380 .title = "Blossom demo: two odd flowers",
381 .nodes = {
382 {-3.00, 1.40, "0"},
383 {-1.60, 2.40, "1"},
384 {-0.40, 1.20, "2"},
385 {-0.70, -0.60, "3"},
386 {-2.40, -0.90, "4"},
387 { 0.80, 0.10, "5"},
388 { 2.10, 1.60, "6"},
389 { 3.20, 0.20, "7"},
390 { 2.40, -1.50, "8"},
391 { 0.30, 2.55, "9"}
392 },
393 .edges = {
394 {0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0},
395 {4, 5}, {5, 6}, {6, 7}, {7, 8}, {8, 5},
396 {2, 5}, {3, 7}, {1, 9}, {6, 9}
397 }
398 };
399
400 cout << "Edmonds-Blossom maximum matching examples\n";
401 cout << "========================================\n";
402
405
406 cout << "\nTo compile a TikZ file to PDF (optional):\n";
407 cout << " cd /tmp && pdflatex blossom_pentagon_stems.tex\n";
408 cout << " cd /tmp && pdflatex blossom_double_flower.tex\n";
409
410 return 0;
411}
Edmonds' Blossom algorithm for maximum matching in general graphs.
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:207
int main()
Program entry that runs two Edmonds–Blossom example scenarios and emits TikZ visualizations.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
Dynamic doubly linked list with O(1) size and bidirectional access.
Dynamic set backed by balanced binary search trees with automatic memory management.
Arc for graphs implemented with simple adjacency lists.
Definition tpl_sgraph.H:197
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:737
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Definition ahTypes.H:121
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.H:89
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
STL namespace.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Array-based graph implementation.
Dynamic array container with automatic resizing.
Dynamic set implementations based on balanced binary search trees.
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.