File indexing completed on 2025-10-18 08:47:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_GRAPH_MAXIMUM_WEIGHTED_MATCHING_HPP
0012 #define BOOST_GRAPH_MAXIMUM_WEIGHTED_MATCHING_HPP
0013
0014 #include <boost/assert.hpp>
0015 #include <boost/optional.hpp>
0016 #include <boost/property_map/property_map.hpp>
0017 #include <boost/range/iterator_range_core.hpp>
0018 #include <boost/graph/exception.hpp>
0019 #include <boost/graph/graph_concepts.hpp>
0020 #include <boost/graph/max_cardinality_matching.hpp> // for empty_matching
0021
0022 #include <algorithm>
0023 #include <deque>
0024 #include <limits>
0025 #include <list>
0026 #include <stack>
0027 #include <tuple> // for std::tie
0028 #include <utility> // for std::pair, std::swap
0029 #include <vector>
0030
0031 namespace boost
0032 {
0033
0034 template <typename Graph, typename MateMap, typename VertexIndexMap>
0035 typename property_traits<
0036 typename property_map<Graph, edge_weight_t>::type>::value_type
0037 matching_weight_sum(const Graph& g, MateMap mate, VertexIndexMap vm)
0038 {
0039 using vertex_iterator_t = typename graph_traits<Graph>::vertex_iterator;
0040 using vertex_descriptor_t = typename graph_traits<Graph>::vertex_descriptor;
0041 using edge_property_t = typename property_traits<
0042 typename property_map<Graph, edge_weight_t>::type>::value_type;
0043
0044 edge_property_t weight_sum = 0;
0045 vertex_iterator_t vi, vi_end;
0046
0047 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
0048 {
0049 vertex_descriptor_t v = *vi;
0050 if (get(mate, v) != graph_traits<Graph>::null_vertex()
0051 && get(vm, v) < get(vm, get(mate, v)))
0052 weight_sum += get(edge_weight, g, edge(v, mate[v], g).first);
0053 }
0054 return weight_sum;
0055 }
0056
0057 template <typename Graph, typename MateMap>
0058 inline typename property_traits<
0059 typename property_map<Graph, edge_weight_t>::type>::value_type
0060 matching_weight_sum(const Graph& g, MateMap mate)
0061 {
0062 return matching_weight_sum(g, mate, get(vertex_index, g));
0063 }
0064
0065
0066
0067
0068 template <typename Graph, typename MateMap, typename VertexIndexMap>
0069 class brute_force_matching
0070 {
0071 public:
0072 using vertex_descriptor_t = typename graph_traits<Graph>::vertex_descriptor;
0073 using vertex_iterator_t = typename graph_traits<Graph>::vertex_iterator;
0074 using vertex_vec_iter_t =
0075 typename std::vector<vertex_descriptor_t>::iterator;
0076 using edge_iterator_t = typename graph_traits<Graph>::edge_iterator;
0077 using vertex_to_vertex_map_t =
0078 boost::iterator_property_map<vertex_vec_iter_t, VertexIndexMap>;
0079
0080 brute_force_matching(
0081 const Graph& arg_g, MateMap arg_mate, VertexIndexMap arg_vm)
0082 : g(&arg_g)
0083 , vm(arg_vm)
0084 , mate_vector(num_vertices(*g))
0085 , best_mate_vector(num_vertices(*g))
0086 , mate(mate_vector.begin(), vm)
0087 , best_mate(best_mate_vector.begin(), vm)
0088 {
0089 vertex_iterator_t vi, vi_end;
0090 for (boost::tie(vi, vi_end) = vertices(*g); vi != vi_end; ++vi)
0091 best_mate[*vi] = mate[*vi] = get(arg_mate, *vi);
0092 }
0093
0094 template <typename PropertyMap> void find_matching(PropertyMap pm)
0095 {
0096 edge_iterator_t ei;
0097 boost::tie(ei, ei_end) = edges(*g);
0098 select_edge(ei);
0099
0100 vertex_iterator_t vi, vi_end;
0101 for (boost::tie(vi, vi_end) = vertices(*g); vi != vi_end; ++vi)
0102 put(pm, *vi, best_mate[*vi]);
0103 }
0104
0105 private:
0106 const Graph* g;
0107 VertexIndexMap vm;
0108 std::vector<vertex_descriptor_t> mate_vector, best_mate_vector;
0109 vertex_to_vertex_map_t mate, best_mate;
0110 edge_iterator_t ei_end;
0111
0112 void select_edge(edge_iterator_t ei)
0113 {
0114 if (ei == ei_end)
0115 {
0116 if (matching_weight_sum(*g, mate)
0117 > matching_weight_sum(*g, best_mate))
0118 {
0119 vertex_iterator_t vi, vi_end;
0120 for (boost::tie(vi, vi_end) = vertices(*g); vi != vi_end; ++vi)
0121 best_mate[*vi] = mate[*vi];
0122 }
0123 return;
0124 }
0125
0126 vertex_descriptor_t v, w;
0127 v = source(*ei, *g);
0128 w = target(*ei, *g);
0129
0130 select_edge(++ei);
0131
0132 if (mate[v] == graph_traits<Graph>::null_vertex()
0133 && mate[w] == graph_traits<Graph>::null_vertex())
0134 {
0135 mate[v] = w;
0136 mate[w] = v;
0137 select_edge(ei);
0138 mate[v] = mate[w] = graph_traits<Graph>::null_vertex();
0139 }
0140 }
0141 };
0142
0143 template <typename Graph, typename MateMap, typename VertexIndexMap>
0144 void brute_force_maximum_weighted_matching(
0145 const Graph& g, MateMap mate, VertexIndexMap vm)
0146 {
0147 empty_matching<Graph, MateMap>::find_matching(g, mate);
0148 brute_force_matching<Graph, MateMap, VertexIndexMap> brute_force_matcher(
0149 g, mate, vm);
0150 brute_force_matcher.find_matching(mate);
0151 }
0152
0153 template <typename Graph, typename MateMap>
0154 inline void brute_force_maximum_weighted_matching(const Graph& g, MateMap mate)
0155 {
0156 brute_force_maximum_weighted_matching(g, mate, get(vertex_index, g));
0157 }
0158
0159 namespace graph
0160 {
0161 namespace detail
0162 {
0163
0164
0165 template <typename Graph, typename VertexIndexMap>
0166 void check_vertex_index_range(const Graph& g, VertexIndexMap vm)
0167 {
0168 using index_t = typename property_traits<VertexIndexMap>::value_type;
0169 using unsigned_index_t = typename std::make_unsigned<index_t>::type;
0170 auto nv = num_vertices(g);
0171 std::vector<bool> got_vertex(nv);
0172 for (const auto& x : make_iterator_range(vertices(g)))
0173 {
0174 index_t i = get(vm, x);
0175 if ((i < 0) || (static_cast<unsigned_index_t>(i) >= nv))
0176 throw bad_graph("Invalid vertex index.");
0177 if (got_vertex[i])
0178 throw bad_graph("Duplicate vertex index.");
0179 got_vertex[i] = true;
0180 }
0181 }
0182
0183
0184 template <typename Graph, typename EdgeWeightMap>
0185 void check_maximum_weighted_matching_edge_weights(
0186 const Graph& g, EdgeWeightMap edge_weights)
0187 {
0188 for (const auto& e : make_iterator_range(edges(g)))
0189 {
0190 auto w = get(edge_weights, e);
0191 auto max_weight = (std::numeric_limits<decltype(w)>::max)() / 4;
0192 if (!(w <= max_weight))
0193 throw bad_graph("Edge weight exceeds maximum supported value.");
0194 }
0195 }
0196
0197
0198 template <typename Graph, typename VertexIndexMap, typename EdgeWeightMap>
0199 struct maximum_weighted_matching_context
0200 {
0201 using vertex_t = typename graph_traits<Graph>::vertex_descriptor;
0202 using edge_t = typename graph_traits<Graph>::edge_descriptor;
0203 using vertices_size_t = typename graph_traits<Graph>::vertices_size_type;
0204 using edges_size_t = typename graph_traits<Graph>::edges_size_type;
0205 using weight_t = typename property_traits<EdgeWeightMap>::value_type;
0206
0207
0208 using vertex_pair_t = std::pair<vertex_t, vertex_t>;
0209
0210
0211
0212
0213
0214
0215
0216
0217 using alternating_path_t = std::deque<vertex_pair_t>;
0218
0219
0220 enum blossom_label_t { LABEL_NONE = 0, LABEL_S = 1, LABEL_T = 2 };
0221
0222 struct nontrivial_blossom_t;
0223
0224
0225
0226
0227
0228 struct blossom_t
0229 {
0230
0231 nontrivial_blossom_t* parent;
0232
0233
0234
0235
0236
0237
0238
0239 vertex_t base_vertex;
0240
0241
0242 blossom_label_t label;
0243
0244
0245 bool is_nontrivial_blossom;
0246
0247
0248 vertex_pair_t tree_edge;
0249
0250
0251 vertex_t tree_root;
0252
0253
0254 optional<edge_t> best_edge;
0255
0256
0257 blossom_t(vertex_t base_vertex = graph_traits<Graph>::null_vertex(),
0258 bool is_nontrivial_blossom = false)
0259 : parent(nullptr)
0260 , base_vertex(base_vertex)
0261 , label(LABEL_NONE)
0262 , is_nontrivial_blossom(is_nontrivial_blossom)
0263 { }
0264
0265
0266
0267
0268
0269 nontrivial_blossom_t* nontrivial()
0270 {
0271
0272 return (is_nontrivial_blossom ?
0273 static_cast<nontrivial_blossom_t*>(this) : nullptr);
0274 }
0275
0276 const nontrivial_blossom_t* nontrivial() const
0277 {
0278 return (is_nontrivial_blossom ?
0279 static_cast<const nontrivial_blossom_t*>(this) : nullptr);
0280 }
0281 };
0282
0283
0284
0285
0286
0287 struct nontrivial_blossom_t : public blossom_t
0288 {
0289 struct sub_blossom_t {
0290
0291 blossom_t* blossom;
0292
0293
0294
0295 vertex_pair_t edge;
0296 };
0297
0298
0299 std::list<sub_blossom_t> subblossoms;
0300
0301
0302 weight_t dual_var;
0303
0304
0305 std::list<edge_t> best_edge_set;
0306
0307
0308 nontrivial_blossom_t(
0309 const std::vector<blossom_t*>& blossoms,
0310 const std::deque<vertex_pair_t>& edges)
0311 : blossom_t(blossoms.front()->base_vertex, true)
0312 , dual_var(0)
0313 {
0314 BOOST_ASSERT(blossoms.size() == edges.size());
0315 BOOST_ASSERT(blossoms.size() % 2 == 1);
0316 BOOST_ASSERT(blossoms.size() >= 3);
0317
0318 auto blossom_it = blossoms.begin();
0319 auto blossom_end = blossoms.end();
0320 auto edge_it = edges.begin();
0321 while (blossom_it != blossom_end) {
0322 subblossoms.push_back({*blossom_it, *edge_it});
0323 ++blossom_it;
0324 ++edge_it;
0325 }
0326 }
0327
0328
0329 std::pair<vertices_size_t, typename std::list<sub_blossom_t>::iterator>
0330 find_subblossom(blossom_t* child)
0331 {
0332 vertices_size_t pos = 0;
0333 auto it = subblossoms.begin();
0334 while (it->blossom != child) {
0335 ++it;
0336 ++pos;
0337 BOOST_ASSERT(it != subblossoms.end());
0338 }
0339 return std::make_pair(pos, it);
0340 }
0341 };
0342
0343
0344 struct delta_step_t
0345 {
0346
0347 int kind;
0348
0349
0350 weight_t value;
0351
0352
0353 edge_t edge;
0354
0355
0356 nontrivial_blossom_t* blossom;
0357 };
0358
0359
0360 template <typename T>
0361 struct vertex_map
0362 {
0363 using key_type = typename property_traits<VertexIndexMap>::key_type;
0364 std::vector<T> vec;
0365 VertexIndexMap vm;
0366
0367 vertex_map(vertices_size_t arg_size, VertexIndexMap arg_vm)
0368 : vec(arg_size)
0369 , vm(arg_vm)
0370 { }
0371
0372 const T& operator[](const key_type& v) const
0373 {
0374 return vec[get(vm, v)];
0375 }
0376
0377 T& operator[](const key_type& v)
0378 {
0379 return vec[get(vm, v)];
0380 }
0381 };
0382
0383
0384 struct least_slack_edge_t
0385 {
0386 optional<edge_t> edge;
0387 weight_t slack;
0388
0389 least_slack_edge_t() : slack(0) {}
0390
0391 void update(const edge_t& e, weight_t s)
0392 {
0393 if ((!edge.has_value()) || (s < slack))
0394 {
0395 edge = e;
0396 slack = s;
0397 }
0398 }
0399 };
0400
0401
0402 static constexpr weight_t weight_factor =
0403 std::numeric_limits<weight_t>::is_integer ? 2 : 1;
0404
0405
0406 const Graph* g;
0407 VertexIndexMap vm;
0408 EdgeWeightMap edge_weights;
0409
0410
0411 vertex_map<vertex_t> vertex_mate;
0412
0413
0414
0415
0416
0417
0418
0419
0420 vertex_map<blossom_t> trivial_blossom;
0421
0422
0423
0424
0425
0426
0427
0428 std::list<nontrivial_blossom_t> nontrivial_blossom;
0429
0430
0431 vertex_map<blossom_t*> vertex_top_blossom;
0432
0433
0434 vertex_map<weight_t> vertex_dual;
0435
0436
0437 vertex_map<optional<edge_t>> vertex_best_edge;
0438
0439
0440 std::deque<vertex_t> scan_queue;
0441
0442
0443 explicit maximum_weighted_matching_context(
0444 const Graph& arg_g, VertexIndexMap arg_vm, EdgeWeightMap weights)
0445 : g(&arg_g)
0446 , vm(arg_vm)
0447 , edge_weights(weights)
0448 , vertex_mate(num_vertices(*g), arg_vm)
0449 , trivial_blossom(num_vertices(*g), arg_vm)
0450 , vertex_top_blossom(num_vertices(*g), arg_vm)
0451 , vertex_dual(num_vertices(*g), arg_vm)
0452 , vertex_best_edge(num_vertices(*g), arg_vm)
0453 {
0454
0455 weight_t max_weight = 0;
0456 for (const edge_t& e : make_iterator_range(edges(*g)))
0457 max_weight = (std::max)(max_weight, get(weights, e));
0458 weight_t init_vertex_dual = max_weight * (weight_factor / 2);
0459
0460 for (const vertex_t& x : make_iterator_range(vertices(*g)))
0461 {
0462 vertex_mate[x] = null_vertex();
0463 trivial_blossom[x].base_vertex = x;
0464 vertex_top_blossom[x] = &trivial_blossom[x];
0465 vertex_dual[x] = init_vertex_dual;
0466 }
0467 }
0468
0469
0470 static vertex_t null_vertex()
0471 {
0472 return graph_traits<Graph>::null_vertex();
0473 }
0474
0475
0476 template <typename Func>
0477 static void for_vertices_in_blossom(const blossom_t& blossom, Func func)
0478 {
0479 auto ntb = blossom.nontrivial();
0480 if (ntb) {
0481
0482
0483 std::vector<const nontrivial_blossom_t*> stack;
0484 stack.push_back(ntb);
0485 while (!stack.empty()) {
0486 auto cur = stack.back();
0487 stack.pop_back();
0488 for (const auto& sub : cur->subblossoms) {
0489 ntb = sub.blossom->nontrivial();
0490 if (ntb) {
0491 stack.push_back(ntb);
0492 } else {
0493 func(sub.blossom->base_vertex);
0494 }
0495 }
0496 }
0497 } else {
0498
0499 func(blossom.base_vertex);
0500 }
0501 }
0502
0503
0504 void update_top_level_blossom(blossom_t& blossom)
0505 {
0506 BOOST_ASSERT(!blossom.parent);
0507 for_vertices_in_blossom(blossom,
0508 [this,&blossom](vertex_t x)
0509 {
0510 vertex_top_blossom[x] = &blossom;
0511 });
0512 }
0513
0514
0515
0516
0517
0518 weight_t edge_slack(const edge_t& e) const
0519 {
0520 vertex_t x = source(e, *g);
0521 vertex_t y = target(e, *g);
0522 weight_t w = get(edge_weights, e);
0523 BOOST_ASSERT(vertex_top_blossom[x] != vertex_top_blossom[y]);
0524 return vertex_dual[x] + vertex_dual[y] - weight_factor * w;
0525 }
0526
0527
0528 void clear_best_edge()
0529 {
0530 for (vertex_t x : make_iterator_range(vertices(*g)))
0531 {
0532 vertex_best_edge[x].reset();
0533 trivial_blossom[x].best_edge.reset();
0534 }
0535
0536 for (nontrivial_blossom_t& b : nontrivial_blossom)
0537 {
0538 b.best_edge.reset();
0539 b.best_edge_set.clear();
0540 }
0541 }
0542
0543
0544 void add_delta2_edge(vertex_t y, const edge_t& e, weight_t slack)
0545 {
0546 auto& best_edge = vertex_best_edge[y];
0547 if ((!best_edge.has_value()) || slack < edge_slack(*best_edge))
0548 best_edge = e;
0549 }
0550
0551
0552 least_slack_edge_t get_least_slack_delta2_edge()
0553 {
0554 least_slack_edge_t best_edge;
0555 for (vertex_t x : make_iterator_range(vertices(*g)))
0556 {
0557 if (vertex_top_blossom[x]->label == LABEL_NONE)
0558 {
0559 const auto& vertex_edge = vertex_best_edge[x];
0560 if (vertex_edge.has_value())
0561 best_edge.update(*vertex_edge, edge_slack(*vertex_edge));
0562 }
0563 }
0564 return best_edge;
0565 }
0566
0567
0568 void add_delta3_edge(blossom_t& b, const edge_t& e, weight_t slack)
0569 {
0570 auto& best_edge = b.best_edge;
0571 if ((!best_edge.has_value()) || slack < edge_slack(*best_edge))
0572 best_edge = e;
0573
0574 auto ntb = b.nontrivial();
0575 if (ntb)
0576 ntb->best_edge_set.push_back(e);
0577 }
0578
0579
0580 void merge_delta3_blossoms(nontrivial_blossom_t& blossom)
0581 {
0582
0583
0584 std::vector<least_slack_edge_t> tmp_best_edge(num_vertices(*g));
0585
0586
0587 for (auto& sub : blossom.subblossoms)
0588 {
0589 blossom_t* b = sub.blossom;
0590 if (b->label == LABEL_S)
0591 {
0592 b->best_edge.reset();
0593 auto ntb = b->nontrivial();
0594 if (ntb)
0595 {
0596
0597 for (const edge_t& e : ntb->best_edge_set)
0598 {
0599 blossom_t* bx = vertex_top_blossom[source(e, *g)];
0600 blossom_t* by = vertex_top_blossom[target(e, *g)];
0601 BOOST_ASSERT(bx == &blossom);
0602
0603 if (bx != by)
0604 {
0605 BOOST_ASSERT(by->label == LABEL_S);
0606 tmp_best_edge[get(vm, by->base_vertex)].update(
0607 e, edge_slack(e));
0608 }
0609 }
0610 ntb->best_edge_set.clear();
0611 }
0612 else
0613 {
0614
0615
0616 for (const edge_t& e :
0617 make_iterator_range(out_edges(b->base_vertex, *g)))
0618 {
0619 BOOST_ASSERT(source(e, *g) == b->base_vertex);
0620 vertex_t y = target(e, *g);
0621 blossom_t* by = vertex_top_blossom[y];
0622
0623
0624 if ((by != &blossom)
0625 && (by->label == LABEL_S)
0626 && (get(edge_weights, e) >= 0))
0627 {
0628 tmp_best_edge[get(vm, by->base_vertex)].update(
0629 e, edge_slack(e));
0630 }
0631 }
0632 }
0633 }
0634 }
0635
0636
0637
0638 BOOST_ASSERT(blossom.best_edge_set.empty());
0639 BOOST_ASSERT(!blossom.best_edge.has_value());
0640 least_slack_edge_t best_edge;
0641 for (const least_slack_edge_t& item : tmp_best_edge)
0642 {
0643 if (item.edge.has_value())
0644 {
0645 blossom.best_edge_set.push_back(*item.edge);
0646 best_edge.update(*item.edge, item.slack);
0647 }
0648 }
0649 blossom.best_edge = best_edge.edge;
0650 }
0651
0652
0653 least_slack_edge_t get_least_slack_delta3_edge()
0654 {
0655 least_slack_edge_t best_edge;
0656
0657 for (vertex_t x : make_iterator_range(vertices(*g)))
0658 {
0659 blossom_t* b = vertex_top_blossom[x];
0660 BOOST_ASSERT(!b->parent);
0661 if ((b->label == LABEL_S) && (b->best_edge.has_value()))
0662 best_edge.update(*b->best_edge, edge_slack(*b->best_edge));
0663 }
0664
0665 return best_edge;
0666 }
0667
0668
0669 void add_vertices_to_scan_queue(blossom_t& blossom)
0670 {
0671 for_vertices_in_blossom(blossom,
0672 [this](vertex_t x)
0673 {
0674 scan_queue.push_back(x);
0675 });
0676 }
0677
0678
0679 alternating_path_t trace_alternating_paths(vertex_t x, vertex_t y)
0680 {
0681
0682 alternating_path_t path;
0683 path.emplace_back(x, y);
0684
0685
0686 while (x != null_vertex())
0687 {
0688 blossom_t* bx = vertex_top_blossom[x];
0689 x = bx->tree_edge.first;
0690 if (x != null_vertex())
0691 path.push_front(bx->tree_edge);
0692 }
0693
0694
0695 while (y != null_vertex())
0696 {
0697 blossom_t* by = vertex_top_blossom[y];
0698 y = by->tree_edge.first;
0699 if (y != null_vertex())
0700 path.emplace_back(by->tree_edge.second, y);
0701 }
0702
0703
0704 while (path.front().second == path.back().first)
0705 {
0706 BOOST_ASSERT(path.size() > 2);
0707 path.pop_front();
0708 path.pop_back();
0709 }
0710
0711
0712 BOOST_ASSERT(path.size() % 2 == 1);
0713
0714 return path;
0715 }
0716
0717
0718 void make_blossom(const alternating_path_t& path)
0719 {
0720 BOOST_ASSERT(path.size() % 2 == 1);
0721 BOOST_ASSERT(path.size() >= 3);
0722
0723
0724 std::vector<blossom_t*> subblossoms;
0725 subblossoms.reserve(path.size());
0726 for (const vertex_pair_t& edge : path)
0727 subblossoms.push_back(vertex_top_blossom[edge.first]);
0728
0729
0730 vertices_size_t pos = 0;
0731 for (const vertex_pair_t& edge : path)
0732 {
0733 pos = (pos + 1) % subblossoms.size();
0734 BOOST_ASSERT(vertex_top_blossom[edge.second] == subblossoms[pos]);
0735 }
0736
0737
0738 nontrivial_blossom.emplace_back(subblossoms, path);
0739 nontrivial_blossom_t& blossom = nontrivial_blossom.back();
0740
0741
0742
0743 for (blossom_t* b : subblossoms)
0744 {
0745 BOOST_ASSERT(!b->parent);
0746 b->parent = &blossom;
0747 if (b->label == LABEL_T)
0748 add_vertices_to_scan_queue(*b);
0749 }
0750
0751
0752 update_top_level_blossom(blossom);
0753
0754
0755 BOOST_ASSERT(subblossoms.front()->label == LABEL_S);
0756 blossom.label = LABEL_S;
0757 blossom.tree_edge = subblossoms.front()->tree_edge;
0758 blossom.tree_root = subblossoms.front()->tree_root;
0759
0760
0761 merge_delta3_blossoms(blossom);
0762 }
0763
0764
0765 void expand_t_blossom(nontrivial_blossom_t* blossom)
0766 {
0767 BOOST_ASSERT(!blossom->parent);
0768 BOOST_ASSERT(blossom->label == LABEL_T);
0769
0770
0771 for (const auto& sub : blossom->subblossoms)
0772 {
0773 blossom_t* b = sub.blossom;
0774 BOOST_ASSERT(b->parent == blossom);
0775 b->parent = nullptr;
0776 b->label = LABEL_NONE;
0777 update_top_level_blossom(*b);
0778 }
0779
0780
0781
0782
0783 blossom_t* entry = vertex_top_blossom[blossom->tree_edge.second];
0784
0785 auto subblossom_loc = blossom->find_subblossom(entry);
0786 auto entry_pos = subblossom_loc.first;
0787 auto entry_it = subblossom_loc.second;
0788
0789
0790 vertex_t x, y;
0791 std::tie(x, y) = blossom->tree_edge;
0792
0793
0794 auto sub_it = entry_it;
0795 if (entry_pos % 2 == 0)
0796 {
0797
0798 auto sub_begin = blossom->subblossoms.begin();
0799 while (sub_it != sub_begin)
0800 {
0801 extend_tree_s_to_t(x, y);
0802 --sub_it;
0803 BOOST_ASSERT(sub_it != sub_begin);
0804 --sub_it;
0805 std::tie(y, x) = sub_it->edge;
0806 }
0807 }
0808 else
0809 {
0810
0811 auto sub_end = blossom->subblossoms.end();
0812 while (sub_it != sub_end) {
0813 extend_tree_s_to_t(x, y);
0814 ++sub_it;
0815 BOOST_ASSERT(sub_it != sub_end);
0816 std::tie(x, y) = sub_it->edge;
0817 ++sub_it;
0818 }
0819 }
0820
0821
0822 blossom_t* base = blossom->subblossoms.front().blossom;
0823 base->label = LABEL_T;
0824 base->tree_edge = std::make_pair(x, y);
0825 base->tree_root = blossom->tree_root;
0826
0827
0828 auto blossom_it = std::find_if(
0829 nontrivial_blossom.begin(),
0830 nontrivial_blossom.end(),
0831 [blossom](const nontrivial_blossom_t& b)
0832 {
0833 return (&b == blossom);
0834 });
0835 BOOST_ASSERT(blossom_it != nontrivial_blossom.end());
0836 nontrivial_blossom.erase(blossom_it);
0837 }
0838
0839 void augment_blossom_rec(
0840 nontrivial_blossom_t& blossom, blossom_t& entry,
0841 std::stack<std::pair<nontrivial_blossom_t*, blossom_t*>>& stack)
0842 {
0843 auto subblossom_loc = blossom.find_subblossom(&entry);
0844 auto entry_pos = subblossom_loc.first;
0845 auto entry_it = subblossom_loc.second;
0846
0847
0848 auto sub_begin = blossom.subblossoms.begin();
0849 auto sub_end = blossom.subblossoms.end();
0850 auto sub_it = entry_it;
0851 while ((sub_it != sub_begin) && (sub_it != sub_end)) {
0852 vertex_t x, y;
0853 blossom_t* bx;
0854 blossom_t* by;
0855
0856 if (entry_pos % 2 == 0)
0857 {
0858
0859 --sub_it;
0860 by = sub_it->blossom;
0861 BOOST_ASSERT(sub_it != sub_begin);
0862 --sub_it;
0863 bx = sub_it->blossom;
0864 std::tie(x, y) = sub_it->edge;
0865 }
0866 else
0867 {
0868
0869 ++sub_it;
0870 BOOST_ASSERT(sub_it != sub_end);
0871 std::tie(x, y) = sub_it->edge;
0872 bx = sub_it->blossom;
0873 ++sub_it;
0874 by = (sub_it == sub_end) ?
0875 blossom.subblossoms.front().blossom :
0876 sub_it->blossom;
0877 }
0878
0879
0880 vertex_mate[x] = y;
0881 vertex_mate[y] = x;
0882
0883
0884 auto bx_ntb = bx->nontrivial();
0885 if (bx_ntb)
0886 stack.emplace(bx_ntb, &trivial_blossom[x]);
0887
0888 auto by_ntb = by->nontrivial();
0889 if (by_ntb)
0890 stack.emplace(by_ntb, &trivial_blossom[y]);
0891 }
0892
0893
0894 if (entry_it != sub_begin)
0895 blossom.subblossoms.splice(
0896 sub_begin, blossom.subblossoms, entry_it, sub_end);
0897 blossom.base_vertex = entry.base_vertex;
0898 }
0899
0900 void augment_blossom(nontrivial_blossom_t& blossom, blossom_t& entry)
0901 {
0902
0903 std::stack<std::pair<nontrivial_blossom_t*, blossom_t*>> stack;
0904 stack.emplace(&blossom, &entry);
0905
0906 while (!stack.empty()) {
0907 nontrivial_blossom_t* outer_blossom;
0908 blossom_t* inner_entry;
0909 std::tie(outer_blossom, inner_entry) = stack.top();
0910
0911 nontrivial_blossom_t* inner_blossom = inner_entry->parent;
0912 BOOST_ASSERT(inner_blossom);
0913
0914 if (inner_blossom != outer_blossom)
0915 stack.top() = std::make_pair(outer_blossom, inner_blossom);
0916 else
0917 stack.pop();
0918
0919 augment_blossom_rec(*inner_blossom, *inner_entry, stack);
0920 }
0921 }
0922
0923
0924 void augment_matching(const alternating_path_t& path)
0925 {
0926 BOOST_ASSERT(path.size() % 2 == 1);
0927
0928
0929 auto path_it = path.begin();
0930 auto path_end = path.end();
0931 while (path_it != path_end)
0932 {
0933 vertex_t x = path_it->first;
0934 vertex_t y = path_it->second;
0935
0936
0937 blossom_t* bx = vertex_top_blossom[x];
0938 auto bx_ntb = bx->nontrivial();
0939 if (bx_ntb)
0940 augment_blossom(*bx_ntb, trivial_blossom[x]);
0941
0942 blossom_t* by = vertex_top_blossom[y];
0943 auto by_ntb = by->nontrivial();
0944 if (by_ntb)
0945 augment_blossom(*by_ntb, trivial_blossom[y]);
0946
0947
0948 vertex_mate[x] = y;
0949 vertex_mate[y] = x;
0950
0951
0952 ++path_it;
0953 if (path_it == path_end)
0954 break;
0955 ++path_it;
0956 }
0957 }
0958
0959
0960
0961
0962
0963 void refresh_scan_queue()
0964 {
0965 std::deque<vertex_t> new_scan_queue;
0966 for (const vertex_t& x : scan_queue)
0967 {
0968 if (vertex_top_blossom[x]->label == LABEL_S)
0969 new_scan_queue.push_back(x);
0970 }
0971 scan_queue = std::move(new_scan_queue);
0972 }
0973
0974
0975 void refresh_delta3_blossom(blossom_t& b)
0976 {
0977
0978 if (!b.best_edge.has_value())
0979 return;
0980
0981 auto ntb = b.nontrivial();
0982 if (ntb)
0983 {
0984
0985 least_slack_edge_t best_edge;
0986 auto it = ntb->best_edge_set.begin();
0987 auto it_end = ntb->best_edge_set.end();
0988 while (it != it_end)
0989 {
0990 vertex_t y = target(*it, *g);
0991 blossom_t* by = vertex_top_blossom[y];
0992 BOOST_ASSERT(by != &b);
0993 if (by->label == LABEL_S)
0994 {
0995 best_edge.update(*it, edge_slack(*it));
0996 ++it;
0997 }
0998 else
0999 {
1000
1001 it = ntb->best_edge_set.erase(it);
1002 }
1003 }
1004 b.best_edge = best_edge.edge;
1005 }
1006 else
1007 {
1008
1009
1010 vertex_t x = b.base_vertex;
1011 vertex_t y = target(*b.best_edge, *g);
1012 blossom_t* by = vertex_top_blossom[y];
1013 BOOST_ASSERT(by != &b);
1014 if (by->label != LABEL_S)
1015 {
1016
1017 least_slack_edge_t best_edge;
1018 for (const edge_t& e : make_iterator_range(out_edges(x, *g)))
1019 {
1020 BOOST_ASSERT(source(e, *g) == x);
1021 y = target(e, *g);
1022 by = vertex_top_blossom[y];
1023 if ((by != &b) && (by->label == LABEL_S))
1024 best_edge.update(e, edge_slack(e));
1025 }
1026 b.best_edge = best_edge.edge;
1027 }
1028 }
1029 }
1030
1031
1032 void recompute_vertex_best_edge(vertex_t x)
1033 {
1034 least_slack_edge_t best_edge;
1035
1036 for (const edge_t& e : make_iterator_range(out_edges(x, *g)))
1037 {
1038 BOOST_ASSERT(source(e, *g) == x);
1039 vertex_t y = target(e, *g);
1040 blossom_t* by = vertex_top_blossom[y];
1041 if (by->label == LABEL_S)
1042 best_edge.update(e, edge_slack(e));
1043 }
1044 vertex_best_edge[x] = best_edge.edge;
1045 }
1046
1047
1048 void remove_alternating_tree(vertex_t r1, vertex_t r2)
1049 {
1050
1051 std::vector<blossom_t*> former_s_blossoms;
1052 for (vertex_t x : make_iterator_range(vertices(*g)))
1053 {
1054 blossom_t* b = vertex_top_blossom[x];
1055 if ((!b->parent)
1056 && (b->label != LABEL_NONE)
1057 && (b->tree_root == r1 || b->tree_root == r2))
1058 {
1059
1060 if (b->label == LABEL_S)
1061 former_s_blossoms.push_back(b);
1062
1063
1064 b->label = LABEL_NONE;
1065 }
1066 }
1067
1068 vertex_map<char> blossom_recompute_best_edge(num_vertices(*g), vm);
1069 vertex_map<char> vertex_recompute_best_edge(num_vertices(*g), vm);
1070
1071
1072 for (blossom_t* b : former_s_blossoms)
1073 {
1074
1075 b->best_edge.reset();
1076 auto ntb = b->nontrivial();
1077 if (ntb)
1078 ntb->best_edge_set.clear();
1079
1080
1081 for_vertices_in_blossom(*b,
1082 [&](vertex_t x)
1083 {
1084
1085 vertex_recompute_best_edge[x] = 1;
1086
1087 for (const edge_t& e :
1088 make_iterator_range(out_edges(x, *g)))
1089 {
1090
1091 BOOST_ASSERT(source(e, *g) == x);
1092 vertex_t y = target(e, *g);
1093 blossom_t* by = vertex_top_blossom[y];
1094 if (by->label == LABEL_S)
1095 blossom_recompute_best_edge[by->base_vertex] = 1;
1096
1097
1098
1099 if (by->label != LABEL_S)
1100 {
1101 const auto& best_edge = vertex_best_edge[y];
1102 if (best_edge.has_value() && (*best_edge == e))
1103 vertex_recompute_best_edge[y] = 1;
1104 }
1105 }
1106 });
1107 }
1108
1109
1110 for (vertex_t x : make_iterator_range(vertices(*g)))
1111 {
1112 if (blossom_recompute_best_edge[x])
1113 refresh_delta3_blossom(*vertex_top_blossom[x]);
1114 }
1115
1116
1117 for (vertex_t x : make_iterator_range(vertices(*g)))
1118 {
1119 if (vertex_recompute_best_edge[x])
1120 recompute_vertex_best_edge(x);
1121 }
1122
1123 refresh_scan_queue();
1124 }
1125
1126
1127
1128
1129
1130
1131
1132
1133 void extend_tree_s_to_t(vertex_t x, vertex_t y)
1134 {
1135 blossom_t* bx = vertex_top_blossom[x];
1136 blossom_t* by = vertex_top_blossom[y];
1137
1138 BOOST_ASSERT(bx->label == LABEL_S);
1139 BOOST_ASSERT(by->label == LABEL_NONE);
1140 by->label = LABEL_T;
1141 by->tree_edge = std::make_pair(x, y);
1142 by->tree_root = bx->tree_root;
1143
1144 vertex_t y2 = by->base_vertex;
1145 vertex_t z = vertex_mate[y2];
1146 BOOST_ASSERT(z != null_vertex());
1147
1148 blossom_t* bz = vertex_top_blossom[z];
1149 BOOST_ASSERT(bz->label == LABEL_NONE);
1150 BOOST_ASSERT(!bz->best_edge.has_value());
1151 bz->label = LABEL_S;
1152 bz->tree_edge = std::make_pair(y2, z);
1153 bz->tree_root = by->tree_root;
1154 add_vertices_to_scan_queue(*bz);
1155 }
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 bool add_s_to_s_edge(vertex_t x, vertex_t y)
1169 {
1170 blossom_t* bx = vertex_top_blossom[x];
1171 blossom_t* by = vertex_top_blossom[y];
1172 BOOST_ASSERT(bx->label == LABEL_S);
1173 BOOST_ASSERT(by->label == LABEL_S);
1174 BOOST_ASSERT(bx != by);
1175
1176 alternating_path_t path = trace_alternating_paths(x, y);
1177
1178
1179 blossom_t* b1 = vertex_top_blossom[path.front().first];
1180 blossom_t* b2 = vertex_top_blossom[path.back().second];
1181 if (b1 == b2)
1182 {
1183 make_blossom(path);
1184 return false;
1185 }
1186 else
1187 {
1188
1189 remove_alternating_tree(bx->tree_root, by->tree_root);
1190
1191
1192 augment_matching(path);
1193 return true;
1194 }
1195 }
1196
1197
1198
1199
1200
1201
1202 bool scan_new_s_vertices()
1203 {
1204 while (!scan_queue.empty())
1205 {
1206 vertex_t x = scan_queue.front();
1207 scan_queue.pop_front();
1208
1209 BOOST_ASSERT(vertex_top_blossom[x]->label == LABEL_S);
1210
1211 for (const edge_t& e : make_iterator_range(out_edges(x, *g)))
1212 {
1213 BOOST_ASSERT(source(e, *g) == x);
1214 vertex_t y = target(e, *g);
1215
1216
1217
1218 blossom_t* bx = vertex_top_blossom[x];
1219 blossom_t* by = vertex_top_blossom[y];
1220
1221
1222 if (bx == by)
1223 continue;
1224
1225
1226 if (get(edge_weights, e) < 0)
1227 continue;
1228
1229 weight_t slack = edge_slack(e);
1230 if (slack <= 0)
1231 {
1232
1233 if (by->label == LABEL_NONE)
1234 extend_tree_s_to_t(x, y);
1235 else if (by->label == LABEL_S)
1236 {
1237 bool augmented = add_s_to_s_edge(x, y);
1238 if (augmented)
1239 return true;
1240 }
1241 }
1242 else
1243 {
1244
1245 if (by->label == LABEL_S)
1246 add_delta3_edge(*bx, e, slack);
1247 }
1248
1249
1250 if (by->label != LABEL_S)
1251 add_delta2_edge(y, e, slack);
1252 }
1253 }
1254
1255 return false;
1256 }
1257
1258
1259 delta_step_t calc_dual_delta_step()
1260 {
1261 delta_step_t delta{};
1262
1263
1264 delta.kind = 1;
1265 delta.value = (std::numeric_limits<weight_t>::max)();
1266 for (vertex_t x : make_iterator_range(vertices(*g)))
1267 {
1268 if (vertex_top_blossom[x]->label == LABEL_S)
1269 delta.value = (std::min)(delta.value, vertex_dual[x]);
1270 }
1271
1272
1273 least_slack_edge_t best_edge = get_least_slack_delta2_edge();
1274 if (best_edge.edge.has_value() && (best_edge.slack <= delta.value))
1275 {
1276 delta.kind = 2;
1277 delta.edge = *best_edge.edge;
1278 delta.value = best_edge.slack;
1279 }
1280
1281
1282 best_edge = get_least_slack_delta3_edge();
1283 if (best_edge.edge.has_value() && (best_edge.slack / 2 <= delta.value))
1284 {
1285 delta.kind = 3;
1286 delta.edge = *best_edge.edge;
1287 delta.value = best_edge.slack / 2;
1288 }
1289
1290
1291 for (nontrivial_blossom_t& blossom : nontrivial_blossom)
1292 {
1293 if ((!blossom.parent)
1294 && (blossom.label == LABEL_T)
1295 && (blossom.dual_var / 2 <= delta.value))
1296 {
1297 delta.kind = 4;
1298 delta.blossom = &blossom;
1299 delta.value = blossom.dual_var / 2;
1300 }
1301 }
1302
1303 return delta;
1304 }
1305
1306
1307 void apply_delta_step(weight_t delta)
1308 {
1309 for (vertex_t x : make_iterator_range(vertices(*g)))
1310 {
1311 blossom_t* b = vertex_top_blossom[x];
1312 if (b->label == LABEL_S)
1313 vertex_dual[x] -= delta;
1314 else if (b->label == LABEL_T)
1315 vertex_dual[x] += delta;
1316 }
1317
1318 for (nontrivial_blossom_t& blossom : nontrivial_blossom)
1319 {
1320 if (!blossom.parent)
1321 {
1322 if (blossom.label == LABEL_S)
1323 blossom.dual_var += 2 * delta;
1324 else if (blossom.label == LABEL_T)
1325 blossom.dual_var -= 2 * delta;
1326 }
1327 }
1328 }
1329
1330
1331
1332
1333
1334
1335
1336 bool run_stage()
1337 {
1338
1339 while (true) {
1340 bool augmented = scan_new_s_vertices();
1341 if (augmented)
1342 return true;
1343
1344 delta_step_t delta = calc_dual_delta_step();
1345 apply_delta_step(delta.value);
1346
1347 if (delta.kind == 2)
1348 {
1349 vertex_t x = source(delta.edge, *g);
1350 vertex_t y = target(delta.edge, *g);
1351 if (vertex_top_blossom[x]->label != LABEL_S)
1352 std::swap(x, y);
1353 extend_tree_s_to_t(x, y);
1354 }
1355 else if (delta.kind == 3)
1356 {
1357 vertex_t x = source(delta.edge, *g);
1358 vertex_t y = target(delta.edge, *g);
1359 augmented = add_s_to_s_edge(x, y);
1360 if (augmented)
1361 return true;
1362 }
1363 else if (delta.kind == 4)
1364 {
1365 BOOST_ASSERT(delta.blossom);
1366 expand_t_blossom(delta.blossom);
1367 }
1368 else
1369 {
1370
1371 BOOST_ASSERT(delta.kind == 1);
1372 return false;
1373 }
1374 }
1375 }
1376
1377
1378 void run()
1379 {
1380
1381 for (vertex_t x : make_iterator_range(vertices(*g)))
1382 {
1383 BOOST_ASSERT(vertex_mate[x] == null_vertex());
1384 blossom_t* bx = vertex_top_blossom[x];
1385 BOOST_ASSERT(bx->label == LABEL_NONE);
1386 BOOST_ASSERT(bx->base_vertex == x);
1387 bx->label = LABEL_S;
1388 bx->tree_edge = std::make_pair(null_vertex(), x);
1389 bx->tree_root = x;
1390 scan_queue.push_back(x);
1391 }
1392
1393
1394 while (run_stage()) ;
1395
1396
1397 scan_queue.clear();
1398 clear_best_edge();
1399 }
1400
1401
1402 template <typename MateMap>
1403 void extract_matching(MateMap mate)
1404 {
1405 for (vertex_t x : make_iterator_range(vertices(*g)))
1406 put(mate, x, vertex_mate[x]);
1407 }
1408 };
1409
1410 }
1411 }
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438 template <typename Graph, typename MateMap, typename VertexIndexMap,
1439 typename EdgeWeightMap>
1440 void maximum_weighted_matching(
1441 const Graph& g, MateMap mate, VertexIndexMap vm, EdgeWeightMap weights)
1442 {
1443 BOOST_CONCEPT_ASSERT((VertexListGraphConcept<Graph>));
1444 BOOST_CONCEPT_ASSERT((EdgeListGraphConcept<Graph>));
1445 BOOST_CONCEPT_ASSERT((IncidenceGraphConcept<Graph>));
1446 BOOST_STATIC_ASSERT(is_undirected_graph<Graph>::value);
1447
1448 using vertex_t = typename graph_traits<Graph>::vertex_descriptor;
1449 using edge_t = typename graph_traits<Graph>::edge_descriptor;
1450 BOOST_CONCEPT_ASSERT((ReadWritePropertyMapConcept<MateMap, vertex_t>));
1451 BOOST_CONCEPT_ASSERT(
1452 (ReadablePropertyMapConcept<VertexIndexMap, vertex_t>));
1453 BOOST_CONCEPT_ASSERT((ReadablePropertyMapConcept<EdgeWeightMap, edge_t>));
1454
1455 graph::detail::check_vertex_index_range(g, vm);
1456 graph::detail::check_maximum_weighted_matching_edge_weights(g, weights);
1457
1458 graph::detail::maximum_weighted_matching_context<
1459 Graph, VertexIndexMap, EdgeWeightMap>
1460 matching(g, vm, weights);
1461 matching.run();
1462 matching.extract_matching(mate);
1463 }
1464
1465
1466
1467
1468
1469
1470 template <typename Graph, typename MateMap, typename VertexIndexMap>
1471 inline void maximum_weighted_matching(
1472 const Graph& g, MateMap mate, VertexIndexMap vm)
1473 {
1474 maximum_weighted_matching(g, mate, vm, get(edge_weight, g));
1475 }
1476
1477
1478
1479
1480
1481
1482
1483 template <typename Graph, typename MateMap>
1484 inline void maximum_weighted_matching(const Graph& g, MateMap mate)
1485 {
1486 maximum_weighted_matching(g, mate, get(vertex_index, g));
1487 }
1488
1489 }
1490
1491 #endif