Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
min_cost_matching_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 <iostream>
54# include <string>
55# include <tuple>
56# include <utility>
57# include <vector>
58
59# include <Min_Cost_Matching.H>
60# include <tpl_agraph.H>
61# include <tpl_dynArray.H>
62# include <tpl_dynSetTree.H>
63# include <tpl_graph.H>
64# include <tpl_sgraph.H>
65
66using namespace std;
67using namespace Aleph;
68
69namespace
70{
72
73 struct Scenario
74 {
75 string title;
76 size_t num_nodes = 0;
78 };
79
80
81 template <class GT>
93 GT build_graph(const Scenario & s)
94 {
95 GT g;
97
98 for (size_t i = 0; i < s.num_nodes; ++i)
99 nodes.append(g.insert_node(static_cast<int>(i)));
100
101 for (const auto & [u, v, cost] : s.edges)
102 g.insert_arc(nodes(u), nodes(v), cost);
103
104 return g;
105 }
106
107
108 template <class GT>
122 {
124
125 for (auto it = matching.get_it(); it.has_curr(); it.next_ne())
126 {
127 auto * arc = it.get_curr();
128 size_t u = static_cast<size_t>(g.get_src_node(arc)->get_info());
129 size_t v = static_cast<size_t>(g.get_tgt_node(arc)->get_info());
130 if (u > v)
131 swap(u, v);
132 sorted_pairs.insert({u, v});
133 }
134
136 for (auto it = sorted_pairs.get_it(); it.has_curr(); it.next_ne())
137 pairs.append(it.get_curr());
138
139 return pairs;
140 }
141
142
153 string format_pairs(const DynArray<pair<size_t, size_t>> & pairs)
154 {
155 if (pairs.is_empty())
156 return "(empty)";
157
158 string out;
159 for (size_t i = 0; i < pairs.size(); ++i)
160 {
161 const auto & p = pairs(i);
162 out += "(" + to_string(p.first) + "," + to_string(p.second) + ")";
163 if (i + 1 < pairs.size())
164 out += " ";
165 }
166
167 return out;
168 }
169
170
171 template <class GT>
194 void print_backend(const string & backend_name,
195 const Scenario & s,
196 bool max_cardinality,
197 long long & canonical_cost,
198 size_t & canonical_cardinality,
199 bool & first_backend)
200 {
201 GT g = build_graph<GT>(s);
203
204 const auto result = blossom_minimum_cost_matching<GT>(
205 g,
206 matching,
207 Dft_Dist<GT>(),
210
211 const auto pairs = extract_pairs(g, matching);
212
213 if (first_backend)
214 {
215 canonical_cost = result.total_cost;
216 canonical_cardinality = result.cardinality;
217 first_backend = false;
218 }
219
220 cout << " " << backend_name
221 << " -> card " << result.cardinality
222 << ", cost " << result.total_cost
223 << " | " << format_pairs(pairs) << '\n';
224
225 if (result.total_cost != canonical_cost
226 or result.cardinality != canonical_cardinality)
227 cerr << " Warning: objective mismatch across backends\n";
228 }
229
230
241 void run_scenario(const Scenario & s)
242 {
243 cout << '\n' << s.title << '\n';
244 cout << string(s.title.size(), '-') << '\n';
245
246 for (const bool max_cardinality : {false, true})
247 {
248 cout << (max_cardinality
249 ? "\nMode: maximum-cardinality then minimum-cost\n"
250 : "\nMode: pure minimum-cost\n");
251
252 long long canonical_cost = 0;
253 size_t canonical_cardinality = 0;
254 bool first_backend = true;
255
262 }
263 }
264
265
266 template <class GT>
278 void print_backend_perfect(const string & backend_name,
279 const Scenario & s)
280 {
281 GT g = build_graph<GT>(s);
284
285 cout << " " << backend_name << " -> feasible "
286 << (result.feasible ? "yes" : "no");
287 if (result.feasible)
288 {
289 const auto pairs = extract_pairs(g, matching);
290 cout << ", card " << result.cardinality
291 << ", cost " << result.total_cost
292 << " | " << format_pairs(pairs);
293 }
294 cout << '\n';
295 }
296
297
306 void run_perfect_demo(const Scenario & s)
307 {
308 cout << '\n' << s.title << " (perfect matching)\n";
309 cout << string(s.title.size() + 19, '-') << '\n';
310
312 "List_Graph", s);
314 "List_SGraph", s);
316 "Array_Graph", s);
317 }
318} // namespace
319
320
321int main()
322{
323 const Scenario scenario{
324 .title = "General min-cost matching (objective-mode demo)",
325 .num_nodes = 6,
326 .edges = {
327 {0, 1, 8},
328 {0, 2, -5},
329 {1, 2, 4},
330 {1, 3, 6},
331 {2, 4, 3},
332 {3, 4, 2},
333 {3, 5, 7},
334 {4, 5, 9},
335 {0, 5, 5},
336 {2, 5, 1}
337 }
338 };
339
340 const Scenario perfect_feasible{
341 .title = "Perfect min-cost matching demo (feasible)",
342 .num_nodes = 4,
343 .edges = {
344 {0, 1, 5},
345 {0, 2, 2},
346 {1, 3, 1},
347 {2, 3, 7}
348 }
349 };
350
351 const Scenario perfect_infeasible{
352 .title = "Perfect min-cost matching demo (infeasible)",
353 .num_nodes = 5,
354 .edges = {
355 {0, 1, 4},
356 {1, 2, 3},
357 {2, 3, 2}
358 }
359 };
360
361 cout << "Dedicated API: blossom_minimum_cost_matching()\n";
362 cout << "Dedicated API: blossom_minimum_cost_perfect_matching()\n";
363 cout << "All costs are edge costs in a non-bipartite graph.\n";
364 run_scenario(scenario);
367
368 return 0;
369}
Minimum-cost matching in general undirected graphs.
int num_nodes
Definition btreepic.C:410
Default distance accessor for arc weights.
size_t size() const noexcept
Return the current dimension of array.
T & append()
Allocate a new entry to the end of array.
bool is_empty() const noexcept
Return true if the array is empty.
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
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.
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1000
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Array-based graph implementation.
Lazy and scalable dynamic array implementation.
Dynamic set implementations based on balanced binary search trees.
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.