Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Min_Cost_Matching.H
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
68# ifndef MIN_COST_MATCHING_H
69# define MIN_COST_MATCHING_H
70
71# include <cstddef>
72# include <limits>
73# include <type_traits>
74# include <utility>
75
76# include <ah-errors.H>
77# include <Blossom_Weighted.H>
78
79namespace Aleph
80{
88 template <typename Cost_Type = long long>
94
95
105 template <typename Cost_Type = long long>
112
113
114 namespace min_cost_matching_detail
115 {
124 template <typename T>
125 long long to_ll_checked(T value)
126 {
127 static_assert(std::is_integral_v<T>,
128 "Min_Cost_Matching requires integral arc costs");
129
130 // Number of value bits in T and in long long (excludes the sign bit).
131 constexpr int T_digits = std::numeric_limits<T>::digits;
132 constexpr int LL_digits = std::numeric_limits<long long>::digits; // 63
133
134 // Upper check: T can hold values > LLONG_MAX when
135 // unsigned T: T_digits >= LL_digits (e.g. unsigned long long: 64 >= 63)
136 // signed T: T_digits > LL_digits (e.g. __int128: 127 > 63)
137 constexpr bool need_upper =
138 std::is_unsigned_v<T> ? (T_digits >= LL_digits)
139 : (T_digits > LL_digits);
140
141 // Lower check: only signed T wider than long long can go below LLONG_MIN.
142 constexpr bool need_lower =
143 std::is_signed_v<T> and (T_digits > LL_digits);
144
145 if constexpr (need_upper)
146 {
147 ah_overflow_error_if(static_cast<__int128>(value)
148 > static_cast<__int128>(std::numeric_limits<long long>::max()))
149 << "Cost cannot be represented as long long";
150 }
151
152 if constexpr (need_lower)
153 {
154 ah_overflow_error_if(static_cast<__int128>(value)
155 < static_cast<__int128>(std::numeric_limits<long long>::min()))
156 << "Cost cannot be represented as long long";
157 }
158
159 return static_cast<long long>(value);
160 }
161
162
166 template <class Cost_Accessor>
168 {
170
171 public:
173 : cost_(std::move(cost))
174 {
175 // empty
176 }
177
178 template <class Arc>
179 long long operator()(Arc *arc) const
180 {
181 const long long c = to_ll_checked(cost_(arc));
182 ah_overflow_error_if(c == std::numeric_limits<long long>::min())
183 << "Minimum-cost matching cannot negate LLONG_MIN cost";
184 return -c;
185 }
186 };
187 } // namespace min_cost_matching_detail
188
189
215 template <class GT,
216 class Cost = Dft_Dist<GT>,
217 class SA = Dft_Show_Arc<GT>>
221 Cost cost = Cost(),
222 SA sa = SA(),
223 const bool max_cardinality = false)
224 {
226 << "compute_minimum_cost_general_matching(): g is a digraph";
227
228 using Arc = typename GT::Arc;
229 using Raw_Cost = std::decay_t<decltype(cost(static_cast<Arc *>(nullptr)))>;
230
231 static_assert(std::is_integral_v<Raw_Cost>,
232 "Min_Cost_Matching requires integral arc costs");
233
234 Cost cost_accessor = std::move(cost);
235
236 const auto weighted_result =
238 GT,
240 SA>(g,
241 matching,
243 std::move(sa),
245
246 long long total_cost = 0;
247 for (auto it = matching.get_it(); it.has_curr(); it.next_ne())
248 {
249 Arc *arc = it.get_curr();
251 const __int128 sum = static_cast<__int128>(total_cost)
252 + static_cast<__int128>(c);
253 ah_overflow_error_if(sum > static_cast<__int128>(std::numeric_limits<long long>::max())
254 or sum < static_cast<__int128>(std::numeric_limits<long long>::min()))
255 << "Minimum-cost matching total cost overflows long long";
256 total_cost = static_cast<long long>(sum);
257 }
258
260 << "Minimum-cost matching internal cardinality mismatch";
261
263 }
264
265
272 template <class GT,
273 class Cost = Dft_Dist<GT>,
274 class SA = Dft_Show_Arc<GT>>
278 Cost cost = Cost(),
279 SA sa = SA(),
280 const bool max_cardinality = false)
281 {
283 g, matching, std::move(cost), std::move(sa),
285 }
286
287
316 template <class GT,
317 class Cost = Dft_Dist<GT>,
318 class SA = Dft_Show_Arc<GT>>
322 Cost cost = Cost(),
323 SA sa = SA())
324 {
326 << "compute_minimum_cost_perfect_general_matching(): g is a digraph";
327
328 matching.empty();
329
330 const size_t num_nodes = g.get_num_nodes();
331 if (num_nodes == 0)
333
334 if (num_nodes % 2 == 1)
336
338 g, matching, std::move(cost), std::move(sa),
339 true);
340
341 const size_t expected = num_nodes / 2;
342 if (best.cardinality != expected)
343 {
344 matching.empty();
346 }
347
349 true, best.total_cost, best.cardinality
350 };
351 }
352
353
360 template <class GT,
361 class Cost = Dft_Dist<GT>,
362 class SA = Dft_Show_Arc<GT>>
366 Cost cost = Cost(),
367 SA sa = SA())
368 {
370 g, matching, std::move(cost), std::move(sa));
371 }
372
373
378 template <class GT,
379 class Cost = Dft_Dist<GT>,
380 class SA = Dft_Show_Arc<GT>>
382 {
385 bool max_cardinality_ = false;
386
387 public:
389 SA sa = SA(),
390 const bool max_cardinality = false)
391 : cost_(std::move(cost)),
392 sa_(std::move(sa)),
394 {
395 // empty
396 }
397
404 };
405
406
411 template <class GT,
412 class Cost = Dft_Dist<GT>,
413 class SA = Dft_Show_Arc<GT>>
433} // namespace Aleph
434
435# endif // MIN_COST_MATCHING_H
Maximum-weight matching in general undirected graphs.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:250
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
WeightedDigraph::Arc Arc
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
int num_nodes
Definition btreepic.C:410
Functor wrapper for minimum-cost general matching.
Compute_Minimum_Cost_General_Matching(Cost cost=Cost(), SA sa=SA(), const bool max_cardinality=false)
Min_Cost_Matching_Result< long long > operator()(const GT &g, DynDlist< typename GT::Arc * > &matching)
Functor wrapper for minimum-cost perfect general matching.
Compute_Minimum_Cost_Perfect_General_Matching(Cost cost=Cost(), SA sa=SA())
Min_Cost_Perfect_Matching_Result< long long > operator()(const GT &g, DynDlist< typename GT::Arc * > &matching)
Default distance accessor for arc weights.
Dynamic doubly linked list with O(1) size and bidirectional access.
Negated_Cost_Accessor(Cost_Accessor cost=Cost_Accessor())
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
bool is_digraph() const noexcept
Return true if the graph this is directed.
Definition graph-dry.H:657
Min_Cost_Perfect_Matching_Result< long long > compute_minimum_cost_perfect_general_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, Cost cost=Cost(), SA sa=SA())
Compute minimum-cost perfect matching in a general undirected graph.
Min_Cost_Matching_Result< long long > compute_minimum_cost_general_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, Cost cost=Cost(), SA sa=SA(), const bool max_cardinality=false)
Compute minimum-cost matching in a general undirected graph.
Blossom_Weighted_Result< long long > compute_maximum_weight_general_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, Weight weight=Weight(), SA sa=SA(), const bool max_cardinality=false)
Compute maximum-weight matching in a general undirected graph.
Min_Cost_Matching_Result< long long > blossom_minimum_cost_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, Cost cost=Cost(), SA sa=SA(), const bool max_cardinality=false)
Alias for compute_minimum_cost_general_matching().
Min_Cost_Perfect_Matching_Result< long long > blossom_minimum_cost_perfect_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, Cost cost=Cost(), SA sa=SA())
Alias for compute_minimum_cost_perfect_general_matching().
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
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::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1000
Result of minimum-cost matching.
Cost_Type total_cost
Sum of matched arc costs.
size_t cardinality
Number of arcs in the matching.
Result of minimum-cost perfect matching.
Cost_Type total_cost
Total cost if feasible.
bool feasible
Whether a perfect matching exists.
size_t cardinality
Cardinality (|V|/2 if feasible).