# include <algorithm>
# include <fstream>
# include <iomanip>
# include <iostream>
# include <string>
# include <utility>
namespace
{
struct Node_Pos
{
double x = 0;
double y = 0;
string label;
};
struct Scenario
{
string slug;
string title;
};
template <class GT>
GT build_graph(
const Scenario & s)
{
for (size_t i = 0; i < s.nodes.size(); ++i)
for (const auto & [u, v] : s.edges)
{
<< "Edge endpoint out of range";
}
return g;
}
template <class GT>
{
for (
auto it = matching.
get_it(); it.has_curr(); it.next_ne())
{
auto * arc = it.get_curr();
size_t u =
static_cast<size_t>(g.
get_src_node(arc)->get_info());
size_t v =
static_cast<size_t>(g.
get_tgt_node(arc)->get_info());
if (u > v)
swap(u, v);
}
for (const auto & p : seen)
return result;
}
{
if (pairs.is_empty())
return "(empty)";
for (size_t i = 0; i < pairs.size(); ++i)
{
const auto & [u, v] = pairs[i];
out +=
"(" + to_string(u) +
"," + to_string(v) +
")";
if (i + 1 < pairs.size())
}
}
void write_tikz(const Scenario & s,
const string & file_path)
{
for (auto [u, v] : matching_pairs)
{
if (u > v)
swap(u, v);
matched_set.
insert(make_pair(u, v));
}
{
cerr << "Cannot write file: " << file_path << endl;
return;
}
out <<
"\\documentclass[tikz,border=10pt]{standalone}\n";
out <<
"\\usepackage{tikz}\n";
out <<
"\\usetikzlibrary{arrows.meta}\n";
out <<
"\\begin{document}\n";
out <<
"\\begin{tikzpicture}[x=1cm,y=1cm]\n";
out <<
" \\fill[blue!2] (-4.2,-3.2) rectangle (4.2,3.2);\n";
out <<
" \\node[font=\\bfseries\\large] at (0,2.95) {"
<< s.title << "};\n";
<< "edge/.style={line width=0.9pt, draw=black!65},"
<< "match/.style={line width=2.6pt, draw=orange!90!black},"
<< "vertex/.style={circle, draw=black!70, fill=white, minimum size=9mm, inner sep=1pt, font=\\small\\bfseries}"
<< "}\n";
for (size_t i = 0; i < s.nodes.size(); ++i)
{
const auto & node = s.nodes[i];
out <<
" \\node[vertex] (n" << i <<
") at ("
<< fixed << setprecision(2) << node.x << "," << node.y << ") {"
<< node.label << "};\n";
}
for (const auto & [u, v] : s.edges)
{
<< "Edge endpoint out of range";
size_t a = u;
size_t b = v;
if (a > b)
swap(a, b);
if (matched_set.
search(make_pair(a, b)) !=
nullptr)
continue;
out <<
" \\draw[edge] (n" << u <<
") -- (n" << v <<
");\n";
}
for (auto [u, v] : matching_pairs)
out <<
" \\draw[match] (n" << u <<
") -- (n" << v <<
");\n";
out <<
" \\node[font=\\small] at (0,-2.95) {matching size = "
<< matching_pairs.size() << "};\n";
out <<
"\\end{tikzpicture}\n";
out <<
"\\end{document}\n";
}
template <class GT>
{
GT g = build_graph<GT>(s);
const size_t cardinality = blossom_maximum_cardinality_matching<GT>(g, matching);
return std::make_pair(cardinality, extract_matching_pairs(g, matching));
}
template <class GT>
void print_backend_result(const string & backend_name,
const Scenario & s,
size_t & cardinality_ref,
bool & is_first)
{
auto [cardinality, pairs] = solve_case<GT>(s);
if (is_first)
{
cardinality_ref = cardinality;
pairs_ref = pairs;
is_first = false;
}
cout << " " << backend_name << " -> size " << cardinality
<< " | " << format_pairs(pairs) << "\n";
if (cardinality != cardinality_ref)
cerr << " Warning: cardinality mismatch across backends\n";
}
void run_scenario(const Scenario & s)
{
cout << "\n" << s.title << "\n";
cout << string(s.title.size(), '-') << "\n";
size_t cardinality = 0;
bool first = true;
"List_Graph", s, cardinality, canonical_pairs, first);
"List_SGraph", s, cardinality, canonical_pairs, first);
"Array_Graph", s, cardinality, canonical_pairs, first);
const string tex_path = "/tmp/blossom_" + s.slug + ".tex";
write_tikz(s, canonical_pairs, tex_path);
cout << " TikZ export: " << tex_path << "\n";
}
}
{
const Scenario pentagon_stems{
.slug = "pentagon_stems",
.title = "Blossom demo: odd cycle + stems",
.nodes = {
{-1.90, 1.10, "0"},
{ 0.00, 2.20, "1"},
{ 1.90, 1.10, "2"},
{ 1.30, -1.10, "3"},
{-1.30, -1.10, "4"},
{-3.10, 2.35, "5"},
{ 3.10, 2.35, "6"},
{ 2.70, -2.05, "7"}
},
.edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0},
{1, 5}, {2, 6}, {3, 7}
}
};
const Scenario double_flower{
.slug = "double_flower",
.title = "Blossom demo: two odd flowers",
.nodes = {
{-3.00, 1.40, "0"},
{-1.60, 2.40, "1"},
{-0.40, 1.20, "2"},
{-0.70, -0.60, "3"},
{-2.40, -0.90, "4"},
{ 0.80, 0.10, "5"},
{ 2.10, 1.60, "6"},
{ 3.20, 0.20, "7"},
{ 2.40, -1.50, "8"},
{ 0.30, 2.55, "9"}
},
.edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 8}, {8, 5},
{2, 5}, {3, 7}, {1, 9}, {6, 9}
}
};
cout << "Edmonds-Blossom maximum matching examples\n";
cout << "========================================\n";
run_scenario(pentagon_stems);
run_scenario(double_flower);
cout << "\nTo compile a TikZ file to PDF (optional):\n";
cout << " cd /tmp && pdflatex blossom_pentagon_stems.tex\n";
cout << " cd /tmp && pdflatex blossom_double_flower.tex\n";
return 0;
}
Edmonds' Blossom algorithm for maximum matching in general graphs.
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
size_t size_t int32_t * out
Simple dynamic array with automatic resizing and functional operations.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Dynamic doubly linked list with O(1) size and bidirectional access.
Dynamic set backed by balanced binary search trees with automatic memory management.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
Key * search(const Key &key) const
Find an element in the set.
Arc for graphs implemented with simple adjacency lists.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
DynArray< Graph::Node * > nodes
Main namespace for Aleph-w library functions.
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Arc of graph implemented with double-linked adjacency lists.
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.