File Coverage

blib/lib/Graph/Matching.pm
Criterion Covered Total %
statement 514 535 96.0
branch 178 204 87.2
condition 114 147 77.5
subroutine 16 18 88.8
pod 2 3 66.6
total 824 907 90.8


line stmt bran cond sub pod time code
1             package Graph::Matching;
2              
3             require 5.006;
4              
5 1     1   64055 use warnings;
  1         3  
  1         34  
6 1     1   7 use strict;
  1         2  
  1         38  
7 1     1   991 use Carp::Assert;
  1         1955  
  1         6  
8 1     1   125 use Exporter qw(import);
  1         1  
  1         7139  
9              
10             our $VERSION = 0.02;
11             our @EXPORT_OK = qw(max_weight_matching edges_from_Graph);
12              
13             =head1 NAME
14              
15             Graph::Matching - Maximum Matching in Graphs
16              
17             =head1 SYNOPSIS
18              
19             Computes maximum matchings in general weighted graphs.
20              
21             A matching is a subset of edges in which no node occurs more than once.
22             The cardinality of a matching is the number of matched edges.
23             The weight of a matching is the sum of the weights of its edges.
24              
25             Example:
26              
27             use Graph::Matching qw(max_weight_matching);
28             my $graph = [ [ 1, 2, 14 ], [ 2, 3, 18 ] ];
29             my %matching = max_weight_matching($graph);
30              
31             =head1 FUNCTION
32              
33             =head2 %m = max_weight_matching($graph [, $maxcardinality ])
34              
35             Compute a maximum-weighted matching in the undirected, weighted graph $graph.
36             If $maxcardinality is true, compute the maximum-cardinality matching
37             with maximum weight among all maximum-cardinality matchings.
38              
39             The graph $graph should be a reference to an array of edges. An edge
40             is described by an arrayref S<[ $v, $w, $weight ]>, containing the two nodes
41             and the weight of the edge. Edges are undirected (usable in both directions).
42             A pair of nodes may have at most one edge between them.
43              
44             The matching is returned as a hash %m, such that $m{$v} == $w if node $v
45             is matched to node $w. Unmatched nodes will not occur as keys of %m.
46              
47             This function takes time O(number_of_nodes ** 3).
48              
49             If all edge weights are integers, the algorithm uses only integer
50             computations. If floating point weights are used, the algorithm could
51             return a slightly suboptimal matching due to numeric precision errors.
52              
53             =head2 $graph = edges_from_Graph($g)
54              
55             Extract a reference to an array of edges, suitable for passing to the
56             max_weight_matching function, from an instance $g of the CPAN Graph module.
57              
58             =head1 NOTES
59              
60             The algorithm is taken from "Efficient Algorithms for Finding Maximum
61             Matching in Graphs" by Zvi Galil, ACM Computing Surveys, 1986.
62             It is based on the "blossom" method for finding augmenting paths and
63             the "primal-dual" method for finding a matching of maximum weight, both
64             methods invented by Jack Edmonds. Some ideas were taken from "Implementation
65             of algorithms for maximum matching on non-bipartite graphs" by H.J. Gabow,
66             Stanford Ph.D. thesis, 1973.
67              
68             =cut
69              
70              
71             # Verify optimized delta2/delta3 computation after every substage;
72             # only works on integer weights; slows down algorithm.
73             our $CHECK_DELTA = 0;
74              
75             # Check optimality of solution before returning; only works on integer weights.
76             our $CHECK_OPTIMUM = 1;
77              
78             # Print lots of debugging messages.
79             our $DBG = 0;
80 0     0 0 0 sub DBG { print STDERR "DEBUG: ", @_, "\n"; }
81              
82              
83             sub max_weight_matching($;$) {
84 23     23 1 22228 my ($graph, $maxcardinality) = @_;
85              
86 23   100     104 $maxcardinality = defined($maxcardinality) && $maxcardinality;
87              
88             #
89             # Vertices are numbered 0 .. ($nvertex-1).
90             # Non-trivial blossoms are numbered nvertex .. (2*$nvertex-1)
91             #
92             # Edges are numbered 0 .. ($nedge-1).
93             # Edge endpoints are numbered 0 .. (2*$nedge-1), such that endpoints
94             # (2*k) and (2*k+1) both belong to the edge with index k.
95             #
96             # Many terms used in the comments come from the paper by Galil.
97             # You will probably need the paper to make sense of this code.
98             #
99              
100             # Don't bother with empty graphs.
101 23         41 my $nedge = scalar(@{$graph});
  23         54  
102 23 100       77 return ( ) if (!$nedge);
103              
104             # Count vertices; map vertices to integers; find maximum edge weight;
105 22         36 my @nodelist;
106             my %nodemap;
107 22         37 my $maxweight = 0;
108 22         36 my $all_integer_weights = 1;
109 22         32 foreach (@{$graph}) {
  22         63  
110 148         204 my ($v, $w, $wt) = @{$_};
  148         311  
111 148         265 foreach ($v, $w) {
112 296 100       807 if (!defined($nodemap{$_})) {
113 143         284 push @nodelist, $_;
114 143         443 $nodemap{$_} = $#nodelist;
115             }
116             }
117 148 100       397 $maxweight = $wt if ($wt > $maxweight);
118 148   100     625 $all_integer_weights = $all_integer_weights && ($wt == int($wt));
119             }
120 22         50 my $nvertex = $#nodelist + 1;
121              
122             # If $p is an endpoint index,
123             # $endpoint[$p] is the vertex index to which endpoint $p is attached.
124 22         35 my @endpoint;
125 22         80 $#endpoint = 2*$nedge-1;
126 22         72 for (my $k = $nedge - 1; $k >= 0; $k--) {
127 148         329 $endpoint[2*$k] = $nodemap{$graph->[$k]->[0]};
128 148         600 $endpoint[2*$k+1] = $nodemap{$graph->[$k]->[1]};
129             }
130              
131             # If $v is a vertex index,
132             # $neighbend[$v] refers to an array of remote endpoints attached to $v.
133 22         30 my @neighbend;
134 22         63 $#neighbend = $nvertex-1;
135 22         75 for (my $k = $nedge - 1; $k >= 0; $k--) {
136 148         226 my $v = $endpoint[2*$k];
137 148         224 my $w = $endpoint[2*$k+1];
138 148         367 assert($v != $w);
139 148         574 push @{$neighbend[$v]}, 2*$k + 1;
  148         330  
140 148         188 push @{$neighbend[$w]}, 2*$k;
  148         512  
141             }
142              
143             # If $v is a vertex index,
144             # $mate[$v] is the remote endpoint of its matched edge, or -1 if $v
145             # is single. (i.e. $endpoint[$mate[$v]] is $v's partner vertex)
146             # Initially all vertices are single.
147 22         76 my @mate = ( -1 ) x $nvertex;
148              
149             # If $b is a top-level blossom,
150             # $label[$b] is 0 if $b is unlabeled (free);
151             # 1 if $b is an S-vertex/blossom;
152             # 2 if $b is a T-vertex/blossom.
153             # The label of a vertex is found by looking at the label of its top-level
154             # containing blossom.
155             # If $v is a vertex inside a T-blossom,
156             # $label[$v] is 2 iff $v is reachable from an S-vertex outside the blossom.
157             # Labels are assigned during a stage and reset after each augmentation.
158 22         76 my @label = ( 0 ) x (2*$nvertex);
159              
160             # If $b is a labeled top-level blossom,
161             # $labelend[$b] is the remote endpoint of the edge through which b obtained
162             # its label, or -1 if $b's base vertex is single.
163             # If $v is a vertex inside a T-blossom and $label[$v] == 2,
164             # $labelend[$v] is the remote endpoint of the edge through which $v is
165             # reachable from outside the blossom.
166 22         72 my @labelend = ( undef ) x (2*$nvertex);
167              
168             # If $v is a vertex,
169             # $inblossom[$v] is the top-level blossom to which $v belongs.
170             # If $v is a top-level vertex, $v is itself a blossom (a trivial blossom)
171             # and $inblossom[$v] == $v.
172             # Initially all vertices are top-level trivial blossoms.
173 22         74 my @inblossom = (0 .. ($nvertex-1));
174              
175             # If $b is a sub-blossom,
176             # $blossomparent[$b] is its immediate parent (sub-)blossom.
177             # If $b is a top-level blossom, $blossomparent[$b] is -1.
178 22         68 my @blossomparent = ( ( -1 ) x $nvertex, ( undef ) x $nvertex );
179              
180             # If $b is a non-trivial (sub-)blossom,
181             # $blossomchilds[$b] refers to an ordered array of its sub-blossoms,
182             # starting with the base and going round the blossom.
183 22         63 my @blossomchilds = ( undef ) x (2*$nvertex);
184              
185             # If $b is a (sub-)blossom,
186             # $blossombase[$b] is its base VERTEX (i.e. recursive sub-blossom).\
187 22         76 my @blossombase = ( 0 .. ($nvertex-1), ( undef ) x $nvertex );
188              
189             # If $b is a non-trivial (sub-)blossom,
190             # $blossomendps[$b] refers to an array of endpoints on its connecting
191             # edges, such that $blossomendps[$b]->[$i] is the local endpoint of
192             # $blossomchilds[$b]->[$i] on the edge that connects it to
193             # $blossomchilds[$b]->[wrap($i+1)].
194 22         62 my @blossomendps = ( undef ) x (2*$nvertex);
195              
196             # If $v is a free vertex (or an unreached vertex inside a T-blossom),
197             # $bestedge[$v] is the remote endpoint on a least-slack edge to an S-vertex
198             # or -1 if there is no such edge.
199             # If $b is a (possibly trivial) top-level S-blossom,
200             # $bestedge[$b] is the remote endpoint on a least-slack edge to a
201             # different S-blossom, or -1 if there is no such edge.
202             # This is used for efficient computation of delta2 and delta3.
203 22         98 my @bestedge = ( -1 ) x (2*$nvertex);
204              
205             # If $b is a non-trivial top-level S-blossom,
206             # $blossombestedges[$b] refers to an array of remote endpoints on
207             # least-slack edges to neighbouring S-blossoms, or is undef() if no
208             # such list has been computed yet.
209             # This is used for efficient computation of delta3.
210 22         61 my @blossombestedges = ( undef ) x (2*$nvertex);
211              
212             # List of currently unused blossom numbers.
213 22         73 my @unusedblossoms = ( $nvertex .. (2*$nvertex-1) );
214              
215             # If $v is a vertex,
216             # $dualvar[$v] = 2 * u($v) where u($v) is $v's variable in the dual
217             # optimization problem (multiplication by two ensures integer values
218             # throughout the algorithm if all edge weights are integers).
219             # If $b is a non-trivial blossom,
220             # $dualvar[$b] = z($b) where z($b) is $b's variable in the dual
221             # optimization problem.
222 22         80 my @dualvar = ( ( $maxweight ) x $nvertex, ( 0 ) x $nvertex );
223              
224             # If $allowedge[$k] is true, edge $k has zero slack in the optimization
225             # problem; if $allowedge[$k] is false, the edge's slack may or may not
226             # be zero.
227 22         56 my @allowedge = ( 0 ) x $nedge;
228              
229             # Queue of newly discovered S-vertices.
230 22         38 my @queue;
231              
232             # slack($k)
233             # returns 2 * slack of edge $k (does not work inside blossoms).
234             local *slack = sub {
235 1977     1977   2568 my ($k) = @_;
236 1977         2757 my $v = $endpoint[2*$k];
237 1977         2953 my $w = $endpoint[2*$k+1];
238 1977         2842 my $weight = $graph->[$k]->[2];
239 1977         5389 return $dualvar[$v] + $dualvar[$w] - 2 * $weight;
240 22         121 };
241              
242             # blossomleaves($b)
243             # returns a list of leaf vertices of (sub-)blossom $b.
244             local *blossomleaves = sub {
245 898     898   1124 my ($b) = @_;
246 898 100       1575 if ($b < $nvertex) {
247 841         1989 return @_;
248             } else {
249 57         70 my @leaves = @{$blossomchilds[$b]};
  57         158  
250 57         90 my $n = 0;
251 57         145 while ($n <= $#leaves) {
252 225         317 $b = shift(@leaves);
253 225 100       406 if ($b < $nvertex) {
254 215         283 push @leaves, $b;
255 215         512 $n++;
256             } else {
257 10         17 unshift @leaves, @{$blossomchilds[$b]};
  10         47  
258             }
259             }
260 57         167 return @leaves;
261             }
262 22         87 };
263              
264             # assignlabel($w, $t, $p)
265             # assigns label $t to the top-level blossom containing vertex $w
266             # and record the fact that $w was reached through the edge with
267             # remote endpoint $p.
268             local *assignlabel = sub {
269 464     464   652 my ($w, $t, $p) = @_;
270 464 50       961 DBG("assignlabel($w,$t,$p)") if ($DBG);
271 464         576 my $b = $inblossom[$w];
272 464   33     2069 assert($label[$w] == 0 && $label[$b] == 0);
273 464         1802 $label[$w] = $t;
274 464         579 $label[$b] = $t;
275 464         533 $labelend[$w] = $p;
276 464         552 $labelend[$b] = $p;
277 464         577 $bestedge[$w] = -1;
278 464         520 $bestedge[$b] = -1;
279 464 100       799 if ($t == 1) {
280             # $b became an S-blossom; add it(s vertices) to the queue
281 404         720 push @queue, blossomleaves($b);
282 404 50       1934 DBG('PUSH ', join(',', blossomleaves($b))) if ($DBG);
283             } else {
284             # $b became a T-blossom; assign label S to its mate.
285             # (If b is a non-trivial blossom, its base is the only vertex
286             # with an external mate.)
287 60         85 my $base = $blossombase[$b];
288 60         143 assert($mate[$base] >= 0);
289 60         363 assignlabel($endpoint[$mate[$base]], 1, $mate[$base] ^ 1);
290             }
291 22         108 };
292              
293             # scanblossom($v, $w)
294             # traces back from vertices $v and $w to discover either a new blossom
295             # or an augmenting path; returns the base vertex of the new blossom or -1.
296             local *scanblossom = sub {
297 91     91   127 my ($v, $w) = @_;
298 91 50       189 DBG("scanblossom($v,$w)") if ($DBG);
299             # Trace back from $v and $w, placing breadcrumbs as we go.
300 91         101 my @path;
301 91         118 my $base = -1;
302 91         210 while ($v != -1) {
303             # Look for a breadcrumb in $v's blossom or put a new breadcrumb.
304 223         299 my $b = $inblossom[$v];
305 223 100       492 if ($label[$b] & 4) {
306 22         34 $base = $blossombase[$b];
307 22         42 last;
308             }
309 201         516 assert($label[$b] == 1);
310 201         784 push @path, $b;
311 201         272 $label[$b] = 5;
312             # Trace one step back.
313 201         493 assert($labelend[$b] == $mate[$blossombase[$b]]);
314 201 100       856 if ($labelend[$b] == -1) {
315             # The base of blossom $b is single; stop tracing this path.
316 160         220 $v = -1;
317             } else {
318 41         59 $v = $endpoint[$labelend[$b]];
319 41         53 $b = $inblossom[$v];
320             # $b is a T-blossom; trace one more step back.
321 41         104 assert($label[$b] == 2);
322 41         186 assert($labelend[$b] >= 0);
323 41         152 $v = $endpoint[$labelend[$b]];
324             }
325             # Swap v and w so that we alternate between both paths.
326 201 100       566 if ($w != -1) {
327 112         133 my $t = $v;
328 112         135 $v = $w;
329 112         318 $w = $t;
330             }
331             }
332             # Remove breadcrumbs.
333 91         169 foreach (@path) {
334 201         384 $label[$_] = 1;
335             }
336             # Return base vertex, if we found one.
337 91         236 return $base;
338 22         115 };
339              
340             # addblossom($base, $k)
341             # constructs a new blossom with given base, containing edge $k which
342             # connects a pair of S vertices; labels the new blossom as S; sets its dual
343             # variable to zero; relabels its T-vertices to S and adds them to the queue.
344             local *addblossom = sub {
345 22     22   75 my ($base, $k) = @_;
346 22         38 my $v = $endpoint[2*$k];
347 22         44 my $w = $endpoint[2*$k+1];
348 22         32 my $bb = $inblossom[$base];
349 22         31 my $bv = $inblossom[$v];
350 22         27 my $bw = $inblossom[$w];
351             # Create blossom.
352 22         33 my $b = pop(@unusedblossoms);
353 22 50       52 DBG("addblossom($base,$k) v=$v w=$w -> b=$b") if ($DBG);
354 22         35 $blossombase[$b] = $base;
355 22         32 $blossomparent[$b] = -1;
356 22         28 $blossomparent[$bb] = $b;
357             # Build lists of sub-blossoms and their interconnecting edge endpoints.
358 22         32 my @path;
359             my @endps;
360             # Trace back from $v to $base.
361 22         58 while ($bv != $bb) {
362             # Add $bv to the new blossom.
363 18         22 $blossomparent[$bv] = $b;
364 18         30 unshift @path, $bv;
365 18         26 unshift @endps, $labelend[$bv];
366             # Trace one step back.
367 18   66     109 assert($label[$bv] == 2 || ($label[$bv] == 1 && $labelend[$bv] == $mate[$blossombase[$bv]]));
368 18         85 assert($labelend[$bv] >= 0);
369 18         63 $v = $endpoint[$labelend[$bv]];
370 18         46 $bv = $inblossom[$v];
371             }
372             # Add the base sub-blossom;
373             # add the edge that connects the pair of S vertices.
374 22         43 unshift @path, $bb;
375 22         33 push @endps, (2*$k);
376             # Trace back from $w to $base.
377 22         65 while ($bw != $bb) {
378             # Add $bw to the new blossom.
379 38         46 $blossomparent[$bw] = $b;
380 38         65 push @path, $bw;
381 38         59 push @endps, ($labelend[$bw] ^ 1);
382             # Trace one step back.
383 38   66     221 assert($label[$bw] == 2 || ($label[$bw] == 1 && $labelend[$bw] == $mate[$blossombase[$bw]]));
384 38         185 assert($labelend[$bw] >= 0);
385 38         139 $w = $endpoint[$labelend[$bw]];
386 38         104 $bw = $inblossom[$w];
387             }
388 22         58 $blossomchilds[$b] = \@path;
389 22         40 $blossomendps[$b] = \@endps;
390             # Set new blossom's label to S.
391 22         97 assert($label[$bb] == 1);
392 22         84 $label[$b] = 1;
393 22         33 $labelend[$b] = $labelend[$bb];
394             # Set dual variable to zero.
395 22         31 $dualvar[$b] = 0;
396             # Relabel vertices.
397 22         47 foreach $v (blossomleaves($b)) {
398 88 100       179 if ($label[$inblossom[$v]] == 2) {
399             # This T-vertex now turns into an S-vertex because it becomes
400             # part of an S-blossom; add it to the queue.
401 28         41 push @queue, $v;
402             }
403 88         151 $inblossom[$v] = $b;
404             }
405             # Compute $blossombestedges[$b].
406 22         91 my @bestedgeto = ( -1 ) x (2*$nvertex);
407 22         41 foreach $bv (@path) {
408 78 100       158 if (!defined($blossombestedges[$bv])) {
409             # This subblossom does not have a list of least-slack edges;
410             # get the information from the vertices.
411 76         139 foreach (blossomleaves($bv)) {
412 82         99 foreach my $p (@{$neighbend[$_]}) {
  82         172  
413 223         290 my $j = $endpoint[$p];
414 223         250 my $bj = $inblossom[$j];
415 223 50 100     979 if ($bj != $b && $label[$bj] == 1 &&
      66        
      66        
416             ($bestedgeto[$bj] == -1 ||
417             slack($p>>1) < slack($bestedgeto[$bj]>>1))) {
418 47         102 $bestedgeto[$bj] = $p;
419             }
420             }
421             }
422             } else {
423             # Walk this subblossom's least-slack edges.
424 2         4 foreach my $p (@{$blossombestedges[$bv]}) {
  2         5  
425 1         3 my $j = $endpoint[$p];
426 1         1 my $bj = $inblossom[$j];
427 1 50 33     12 if ($bj != $b && $label[$bj] == 1 &&
      33        
      33        
428             ($bestedgeto[$bj] == -1 ||
429             slack($p>>1) < slack($bestedgeto[$bj]>>1))) {
430 1         3 $bestedgeto[$bj] = $p;
431             }
432             }
433             }
434             # Forget about least-slack edges of the subblossom.
435 78         140 $blossombestedges[$bv] = undef;
436 78         151 $bestedge[$bv] = -1;
437             }
438 22         47 @bestedgeto = grep { $_ != -1 } @bestedgeto;
  340         654  
439 22         44 $blossombestedges[$b] = \@bestedgeto;
440             # Select bestedge[b].
441 22         32 $bestedge[$b] = -1;
442 22         42 foreach my $p (@bestedgeto) {
443 47 100 100     154 if ($bestedge[$b] == -1 ||
444             slack($p>>1) < slack($bestedge[$b]>>1)) {
445 21         49 $bestedge[$b] = $p;
446             }
447             }
448 22 50       73 DBG("blossomchilds[$b] = ", join(',', @path)) if ($DBG);
449 22 50       187 DBG("blossomendps[$b] = ", join('; ', map { $endpoint[$_] . "," . $endpoint[$_^1] } @{$blossomendps[$b]})) if ($DBG);
  0         0  
  0         0  
450 22         151 };
451              
452             # expandblossom($b, $endstage)
453             # expands the given top-level blossom.
454             local *expandblossom = sub {
455 7     7   16 my ($b, $endstage) = @_;
456 7 50       21 DBG("expandblossom($b,$endstage) ", join(',', @{$blossomchilds[$b]})) if ($DBG);
  0         0  
457             # Convert sub-blossoms into top-level blossoms.
458 7         11 foreach my $s (@{$blossomchilds[$b]}) {
  7         21  
459 31         38 $blossomparent[$s] = -1;
460 31 100 33     61 if ($s < $nvertex) {
    50          
461 29         131 $inblossom[$s] = $s;
462             } elsif ($endstage && $dualvar[$s] == 0) {
463             # Recursively expand this sub-blossom.
464 0         0 expandblossom($s, $endstage);
465             } else {
466 2         5 foreach (blossomleaves($s)) {
467 6         14 $inblossom[$_] = $s;
468             }
469             }
470             }
471             # If we expand a T-blossom during a stage, its sub-blossoms must be
472             # relabeled.
473 7 100 66     40 if (!$endstage && $label[$b] == 2) {
474             # Start at the sub-blossom through which the expanding
475             # blossom obtained its label, and relabel sub-blossoms until
476             # we reach the base.
477             # Figure out through which sub-blossom the expanding blossom
478             # obtained its label initially.
479 6         22 assert($labelend[$b] >= 0);
480 6         30 my $entrychild = $inblossom[$endpoint[$labelend[$b] ^ 1]];
481             # Decide in which direction we will go round the blossom.
482 6         11 my $j = 0;
483 6         17 my $jstep;
484 6         38 $j++ until ($blossomchilds[$b]->[$j] == $entrychild);
485 6 100       30 if ($j & 1) {
486             # Start index is odd; go forward and wrap.
487 4         7 $j -= scalar(@{$blossomchilds[$b]});
  4         7  
488 4         8 $jstep = 1;
489             } else {
490             # Start index is even; go backward.
491 2         6 $jstep = -1;
492             }
493             # Move along the blossom until we get to the base.
494 6         11 my $p = $labelend[$b];
495 6         16 while ($j != 0) {
496             # Relabel the T-sub-blossom.
497 7 100       21 my $q = ($jstep == 1) ? ($blossomendps[$b]->[$j]) :
498             ($blossomendps[$b]->[$j-1]^1);
499 7         17 $label[$endpoint[$p^1]] = 0;
500 7         12 $label[$endpoint[$q^1]] = 0;
501 7         21 assignlabel($endpoint[$p^1], 2, $p);
502             # Step to the next S-sub-blossom and note its forward endpoint.
503 7         12 $allowedge[$q>>1] = 1;
504 7         11 $j += $jstep;
505 7 100       23 $p = ($jstep == 1) ? ($blossomendps[$b]->[$j]) :
506             ($blossomendps[$b]->[$j-1]^1);
507             # Step to the next T-sub-blossom.
508 7         11 $allowedge[$p>>1] = 1;
509 7         19 $j += $jstep;
510             }
511             # Relabel the base T-sub-blossom WITHOUT stepping through to
512             # its mate (so don't call assignlabel).
513 6         13 my $bv = $blossomchilds[$b]->[$j];
514 6         14 $label[$endpoint[$p^1]] = 2;
515 6         9 $label[$bv] = 2;
516 6         12 $labelend[$endpoint[$p^1]] = $p;
517 6         9 $labelend[$bv] = $p;
518 6         7 $bestedge[$bv] = -1;
519             # Continue along the blossom until we get back to entrychild.
520 6         14 $j += $jstep;
521 6         22 while ($blossomchilds[$b]->[$j] != $entrychild) {
522             # Examine the vertices of the sub-blossom to see whether
523             # it is reachable from a neighbouring S-vertex outside the
524             # expanding blossom.
525 8         13 $bv = $blossomchilds[$b]->[$j];
526 8 50       17 if ($label[$bv] == 1) {
527             # This sub-blossom just got label S through one of its
528             # neighbours; leave it.
529 0         0 $j += $jstep;
530 0         0 next;
531             }
532 8         10 my $v;
533 8         17 foreach (blossomleaves($bv)) {
534 8 100       29 if ($label[$_] != 0) {
535 2         5 $v = $_;
536 2         5 last;
537             }
538             }
539             # If the sub-blossom contains a reachable vertex, assign
540             # label T to the sub-blossom.
541 8 100       20 if (defined($v)) {
542 2         7 assert($label[$v] == 2);
543 2         13 assert($inblossom[$v] == $bv);
544 2         8 $label[$v] = 0;
545 2         6 $label[$endpoint[$mate[$blossombase[$bv]]]] = 0;
546 2         5 assignlabel($v, 2, $labelend[$v]);
547             }
548 8         26 $j += $jstep;
549             }
550             }
551             # Recycle the blossom number.
552 7         11 $label[$b] = undef;
553 7         10 $labelend[$b] = undef;
554 7         10 $blossomparent[$b] = undef;
555 7         10 $blossomchilds[$b] = undef;
556 7         13 $blossomendps[$b] = undef;
557 7         14 $blossombase[$b] = undef;
558 7         9 $blossombestedges[$b] = undef;
559 7         12 $bestedge[$b] = undef;
560 7         23 push @unusedblossoms, $b;
561 22         122 };
562              
563             # augmentblossom($b, $v)
564             # swaps matched/unmatched edges over an alternating path through blossom $b
565             # between vertex $v and the base vertex; keeps blossom structure consistent.
566             local *augmentblossom = sub {
567 29     29   46 my ($b, $v) = @_;
568 29 50       69 DBG("augmentblossom($b,$v)") if ($DBG);
569             # Bubble up through the blossom tree from vertex v to an immediate
570             # sub-blossom of b.
571 29         44 my $t = $v;
572 29         81 $t = $blossomparent[$t] until ($blossomparent[$t] == $b);
573             # Recursively deal with the first sub-blossom.
574 29 100       84 augmentblossom($t, $v) if ($t >= $nvertex);
575             # Decide in which direction we will go round the blossom.
576 29         52 my $i = 0;
577 29         133 $i++ until ($blossomchilds[$b]->[$i] == $t);
578 29         40 my $j = $i;
579 29         38 my $jstep;
580 29 100       74 if ($i & 1) {
581             # Start index is odd; go forward and wrap.
582 7         11 $j -= scalar(@{$blossomchilds[$b]});
  7         15  
583 7         13 $jstep = 1;
584             } else {
585             # Start index is even; go backward.
586 22         47 $jstep = -1;
587             }
588             # Move along the blossom until we get to the base.
589 29         90 while ($j != 0) {
590             # Step to the next sub-blossom and augment it recursively.
591 13         16 $j += $jstep;
592 13         22 $t = $blossomchilds[$b]->[$j];
593 13 100       39 my $p = ($jstep == 1) ? ($blossomendps[$b]->[$j]) :
594             ($blossomendps[$b]->[$j-1]^1);
595 13 50       28 augmentblossom($t, $endpoint[$p]) if ($t >= $nvertex);
596             # Step to the next sub-blossom and augment it recursively.
597 13         20 $j += $jstep;
598 13         18 $t = $blossomchilds[$b]->[$j];
599 13 100       53 augmentblossom($t, $endpoint[$p^1]) if ($t >= $nvertex);
600             # Match the edge connecting those sub-blossoms.
601 13         37 $mate[$endpoint[$p]] = $p ^ 1;
602 13         24 $mate[$endpoint[$p^1]] = $p;
603 13 50       52 DBG("PAIR ", $endpoint[$p], " ", $endpoint[$p^1], " k=", $p>>1) if ($DBG);
604             }
605             # Rotate the list of sub-blossoms to put the new base at the front.
606 29         49 my $n = scalar(@{$blossomchilds[$b]});
  29         63  
607 29         73 $blossomchilds[$b] = [ @{$blossomchilds[$b]}[$i .. ($n-1)],
  29         87  
608 29         70 @{$blossomchilds[$b]}[0 .. ($i-1)] ];
609 29         64 $blossomendps[$b] = [ @{$blossomendps[$b]}[$i .. ($n-1)],
  29         79  
610 29         87 @{$blossomendps[$b]}[0 .. ($i-1)] ];
611 29         75 $blossombase[$b] = $blossombase[$blossomchilds[$b]->[0]];
612 29         99 assert($blossombase[$b] == $v);
613 22         138 };
614              
615             # augmentmatching($k)
616             # swaps matched/unmatched edges over an alternating path between two
617             # single vertices; the augmenting path runs through edge $k, which
618             # connects a pair of S vertices.
619             local *augmentmatching = sub {
620 69     69   101 my ($k) = @_;
621 69         114 my $v = $endpoint[2*$k];
622 69         118 my $w = $endpoint[2*$k+1];
623 69 50       151 DBG("augmentmatching($k) v=$v w=$w") if ($DBG);
624 69 50       133 DBG("PAIR $v $w k=$k") if ($DBG);
625 69         164 foreach my $p (2*$k+1, 2*$k) {
626 138         232 my $s = $endpoint[$p^1];
627             # Match vertex s to remote endpoint p. Then trace back from s
628             # until we find a single vertex, swapping matched and unmatched
629             # edges as we go.
630 138         170 while (1) {
631 151         199 my $bs = $inblossom[$s];
632 151   33     758 assert($label[$bs] == 1 &&
633             $labelend[$bs] == $mate[$blossombase[$bs]]);
634             # Augment through the S-blossom from s to base.
635 151 100       1308 augmentblossom($bs, $s) if ($bs >= $nvertex);
636             # Update $mate[$s]
637 151         266 $mate[$s] = $p;
638             # Trace one step back.
639 151 100       542 last if ($labelend[$bs] == -1); # stop at single vertex
640 13         27 my $t = $endpoint[$labelend[$bs]];
641 13         19 my $bt = $inblossom[$t];
642 13         53 assert($label[$bt] == 2);
643             # Trace one step back.
644 13         65 assert($labelend[$bt] >= 0);
645 13         52 $s = $endpoint[$labelend[$bt]];
646 13         26 my $j = $endpoint[$labelend[$bt] ^ 1];
647             # Augment through the T-blossom from j to base.
648 13         45 assert($blossombase[$bt] == $t);
649 13 100       65 augmentblossom($bt, $j) if ($bt >= $nvertex);
650             # Update $mate[$j]
651 13         37 $mate[$j] = $labelend[$bt];
652             # Keep the opposite endpoint;
653             # it will be assigned to $mate[$s] in the next step.
654 13         20 $p = $labelend[$bt] ^ 1;
655 13 50       38 DBG("PAIR $s $t k=", $p>>1) if ($DBG);
656             }
657             }
658 22         115 };
659              
660             # Verify that the optimum solution has been reached.
661             local *verifyoptimum = sub {
662 21     21   32 my $vdualoffset = 0;
663 21 100       54 if ($maxcardinality) {
664             # Vertices may have negative dual;
665             # find a constant non-negative number to add to all vertex duals.
666 2         7 foreach (@dualvar[0..($nvertex-1)]) {
667 8 100       23 $vdualoffset = -$_ if ($_ < -$vdualoffset);
668             }
669             }
670             # 0. all dual variables are non-negative
671 21         94 foreach (@dualvar[0 .. ($nvertex-1)]) {
672 139         601 assert($_ + $vdualoffset >= 0);
673             }
674 21         154 foreach (@dualvar[$nvertex .. (2*$nvertex-1)]) {
675 139   33     867 assert(!defined($_) || $_ >= 0);
676             }
677             # 0. all edges have non-negative slack and
678             # 1. all matched edges have zero slack;
679 21         135 foreach my $k (0 .. ($nedge-1)) {
680 144         402 my $v = $endpoint[2*$k];
681 144         217 my $w = $endpoint[2*$k+1];
682 144         232 my $weight = $graph->[$k]->[2];
683 144         243 my $s = $dualvar[$v] + $dualvar[$w] - 2 * $weight;
684 144         234 my @vblossoms = ( $v );
685 144         201 my @wblossoms = ( $w );
686 144         459 push @vblossoms, $blossomparent[$vblossoms[-1]]
687             until ($blossomparent[$vblossoms[-1]] == -1);
688 144         377 push @wblossoms, $blossomparent[$wblossoms[-1]]
689             until ($blossomparent[$wblossoms[-1]] == -1);
690 144   33     630 while ($#vblossoms >= 0 && $#wblossoms >= 0) {
691 197         274 my $bv = pop(@vblossoms);
692 197         233 my $bw = pop(@wblossoms);
693 197 100       449 last if ($bv != $bw);
694 53         261 $s += 2 * $dualvar[$bv];
695             }
696 144         344 assert($s >= 0);
697 144 100 66     977 if ($mate[$v]>>1 == $k || $mate[$w]>>1 == $k) {
698 67   33     328 assert($mate[$v]>>1 == $k && $mate[$w]>>1 == $k);
699 67         296 assert($s == 0);
700             }
701             }
702             # 2. all single vertices have zero dual value;
703 21         133 foreach my $v (0 .. ($nvertex-1)) {
704 139   66     700 assert($mate[$v] >= 0 || $dualvar[$v] + $vdualoffset == 0);
705             }
706             # 3. all blossoms with positive dual value are full.
707 21         130 foreach my $b ($nvertex .. (2*$nvertex-1)) {
708 139 100 100     386 if (defined($blossombase[$b]) && $dualvar[$b] > 0) {
709 12         20 assert((scalar(@{$blossomendps[$b]}) & 1) == 1);
  12         57  
710 12         54 for (my $j = 1; $j <= $#{$blossomendps[$b]}; $j += 2) {
  25         143  
711 13         26 my $p = $blossomendps[$b]->[$j];
712 13         42 assert($mate[$endpoint[$p]] == ($p^1));
713 13         72 assert($mate[$endpoint[$p^1]] == $p);
714             }
715             }
716             }
717             # Ok.
718 22         123 };
719              
720             # Check optimized delta2 against a trivial computation.
721             local *checkdelta2 = sub {
722 104     104   243 foreach my $v (0 .. ($nvertex-1)) {
723 806 100       2696 if ($label[$inblossom[$v]] == 0) {
724 256         312 my $bd;
725 256         270 foreach my $p (@{$neighbend[$v]}) {
  256         572  
726 587         724 my $w = $endpoint[$p];
727 587 100       1557 if ($label[$inblossom[$w]] == 1) {
728 101         211 my $d = slack($p >> 1);
729 101 100 100     445 $bd = $d if (!defined($bd) || $d < $bd);
730             }
731             }
732 256   66     1479 assert((!defined($bd) && $bestedge[$v] == -1) || ($bestedge[$v] != -1 && $bd == slack($bestedge[$v]>>1)));
733             }
734             }
735 22         102 };
736              
737             # Check optimized delta3 against a trivial computation.
738             local *checkdelta3 = sub {
739 104     104   132 my ($bd, $tbd);
740 104         230 foreach my $b (0 .. (2*$nvertex-1)) {
741 1612 100 100     6857 if (defined($blossomparent[$b]) && $blossomparent[$b] == -1 &&
      100        
742             $label[$b] == 1) {
743 386         718 foreach my $v (blossomleaves($b)) {
744 456         523 foreach my $p (@{$neighbend[$v]}) {
  456         972  
745 840         1118 my $w = $endpoint[$p];
746 840 100 100     3755 if ($inblossom[$w] != $b && $label[$inblossom[$w]] == 1) {
747 398         854 my $d = slack($p>>1);
748 398 100 100     2295 $bd = $d if (!defined($bd) || $d < $bd);
749             }
750             }
751             }
752 386 100       1127 if ($bestedge[$b] != -1) {
753 247         369 my $w = $endpoint[$bestedge[$b]];
754 247         385 my $v = $endpoint[$bestedge[$b]^1];
755 247         651 assert($inblossom[$v] == $b);
756 247         1174 assert($inblossom[$w] != $b);
757 247   33     1718 assert($label[$inblossom[$w]] == 1 && $label[$inblossom[$v]] == 1);
758 247         1121 my $d = slack($bestedge[$b]>>1);
759 247 100 100     1297 $tbd = $d if (!defined($tbd) || $d < $tbd);
760             }
761             }
762             }
763 104   66     625 assert((!defined($bd) && !defined($tbd)) || ($bd == $tbd));
764 22         118 };
765              
766             # Main loop: continue until no further improvement is possible.
767 22         40 for (my $t = 0; ; $t++) {
768              
769             # Each iteration of this loop is a "stage".
770             # A stage finds an augmenting path and uses that to improve
771             # the matching.
772 91 50       226 DBG("STAGE $t") if ($DBG);
773              
774             # Remove labels from top-level blossoms/vertices.
775 91 100       172 foreach (@label) { $_ = 0 if (defined($_)); }
  1356         2946  
776              
777             # Forget all about least-slack edges.
778 91 100       172 foreach (@bestedge) { $_ = -1 if (defined($_)); }
  1356         3034  
779 91         161 foreach (@blossombestedges) { $_ = undef; }
  1356         1834  
780              
781             # Loss of labeling means that we can not be sure that currently
782             # allowable edges remain allowable througout this stage.
783 91         155 foreach (@allowedge) { $_ = 0; }
  711         980  
784              
785             # Make queue empty.
786 91         182 @queue = ( );
787            
788             # Label single blossoms/vertices with S and put them in the queue.
789 91         241 for (my $v = 0; $v < $nvertex; $v++) {
790 678 100 66     2557 if ($mate[$v] == -1 && $label[$inblossom[$v]] == 0) {
791 344         719 assignlabel($v, 1, -1);
792             }
793             }
794              
795             # Loop until we succeed in augmenting the matching.
796 91         121 my $augmented = 0;
797 91         103 while (1) {
798              
799             # Each iteration of this loop is a "substage".
800             # A substage tries to find an augmenting path;
801             # if found, the path is used to improve the matching and
802             # the stage ends. If there is no augmenting path, the
803             # primal-dual method is used to pump some slack out of
804             # the dual variables.
805 177 50       348 DBG("SUBSTAGE") if ($DBG);
806              
807             # Continue labeling until all vertices which are reachable
808             # through an alternating path have got a label.
809 177   100     773 while (@queue && !$augmented) {
810              
811             # Take an S vertex from the queue.
812 443         687 my $v = pop(@queue);
813 443 50       894 DBG("POP v=$v") if ($DBG);
814 443         1174 assert($label[$inblossom[$v]] == 1);
815              
816             # Scan its neighbours:
817 443         1591 foreach my $p (@{$neighbend[$v]}) {
  443         980  
818             # w is a neighbour to v
819 815         1043 my $w = $endpoint[$p];
820             # ignore blossom-internal edges
821 815 100       1923 next if ($inblossom[$v] == $inblossom[$w]);
822             # check whether edge has zero slack
823 704         825 my $kslack;
824 704 100       1560 if (!$allowedge[$p>>1]) {
825 601         1226 $kslack = slack($p>>1);
826 601         1175 $allowedge[$p>>1] = ($kslack == 0);
827             }
828 704 100       1894 if ($allowedge[$p>>1]) {
    100          
    100          
829 217 100       796 if ($label[$inblossom[$w]] == 0) {
    100          
    100          
830             # (C1) w is a free vertex;
831             # label w with T and label its mate with S (R12).
832 51         120 assignlabel($w, 2, $p ^ 1);
833             } elsif ($label[$inblossom[$w]] == 1) {
834             # (C2) w is an S-vertex (not in the same blossom);
835             # follow back-links to discover either an
836             # augmenting path or a new blossom.
837 91         202 my $base = scanblossom($v, $w);
838 91 100       190 if ($base >= 0) {
839             # Found a new blossom; add it to the blossom
840             # bookkeeping and turn it into an S-blossom.
841 22         59 addblossom($base, $p>>1);
842             } else {
843             # Found an augmenting path; augment the
844             # matching and end this stage.
845 69         165 augmentmatching($p>>1);
846 69         130 $augmented = 1;
847 69         333 last;
848             }
849             } elsif ($label[$w] == 0) {
850             # w is inside a T-blossom, but w itself has not
851             # yet been reached from outside the blossom;
852             # mark it as reached (we need this to relabel
853             # during T-blossom expansion).
854 12         37 assert($label[$inblossom[$w]] == 2);
855 12         46 $label[$w] = 2;
856 12         71 $labelend[$w] = $p ^ 1;
857             }
858             } elsif ($label[$inblossom[$w]] == 1) {
859             # keep track of the least-slack non-allowable edge to
860             # a different S-blossom.
861 356         467 my $b = $inblossom[$v];
862 356 100 100     1010 if ($bestedge[$b] == -1 ||
863             $kslack < slack($bestedge[$b]>>1)) {
864 289         1239 $bestedge[$b] = $p;
865             }
866             } elsif ($label[$w] == 0) {
867             # w is a free vertex (or an unreached vertex inside
868             # a T-blossom) but we can not reach it yet;
869             # keep track of the least-slack edge that reaches w.
870 130 100 100     361 if ($bestedge[$w] == -1 ||
871             $kslack < slack($bestedge[$w]>>1)) {
872 122         676 $bestedge[$w] = $p ^ 1;
873             }
874             }
875             }
876              
877             }
878              
879 177 100       390 last if ($augmented);
880              
881             # There is no augmenting path under these constraints;
882             # compute delta and reduce slack in the optimization problem.
883             # (Note that our vertex dual variables, edge slacks and delta's
884             # are pre-multiplied by two.)
885 108         130 my $deltatype = -1;
886 108         131 my ($delta, $deltaedge, $deltablossom);
887              
888             # Verify data structures for delta2/delta3 computation.
889 108 100       331 checkdelta2() if ($CHECK_DELTA);
890 108 100       436 checkdelta3() if ($CHECK_DELTA);
891              
892             # Compute delta1: the minumum value of any vertex dual.
893 108 100       548 if (!$maxcardinality) {
894 102         138 $deltatype = 1;
895 102         133 $delta = $dualvar[0];
896 102         357 foreach (@dualvar[0 .. ($nvertex-1)]) {
897 798 100       1758 $delta = $_ if ($_ < $delta);
898             }
899             }
900              
901             # Compute delta2: the minimum slack on any edge between
902             # an S-vertex and a free vertex.
903 108         321 for (my $v = 0; $v < $nvertex; $v++) {
904 822 100 100     3236 if ($label[$inblossom[$v]] == 0 && $bestedge[$v] != -1) {
905 83         173 my $d = slack($bestedge[$v]>>1);
906 83 100 100     432 if ($deltatype == -1 || $d < $delta) {
907 40         53 $deltatype = 2;
908 40         51 $delta = $d;
909 40         123 $deltaedge = $bestedge[$v];
910             }
911             }
912             }
913              
914             # Compute delta3: half the minimum slack on any edge between
915             # a pair of S-blossoms.
916 108         301 for (my $b = 0; $b < 2*$nvertex; $b++) {
917 1644 100 100     13694 if (defined($blossomparent[$b]) && $blossomparent[$b] == -1 &&
      100        
      100        
918             $label[$b] == 1 && $bestedge[$b] != -1) {
919 250         554 my $d = slack($bestedge[$b]>>1) / 2;
920 250 100 100     1520 if ($deltatype == -1 || $d < $delta) {
921 67         77 $deltatype = 3;
922 67         83 $delta = $d;
923 67         217 $deltaedge = $bestedge[$b];
924             }
925             }
926             }
927              
928             # Compute delta4: minimum z variable of any T-blossom.
929 108         294 for (my $b = $nvertex; $b < 2*$nvertex; $b++) {
930 822 100 100     3069 if (defined($blossombase[$b]) && $blossomparent[$b] == -1 &&
      100        
      66        
      66        
931             $label[$b] == 2 &&
932             ($deltatype == -1 || $dualvar[$b] < $delta)) {
933 6         9 $deltatype = 4;
934 6         10 $delta = $dualvar[$b];
935 6         18 $deltablossom = $b;
936             }
937             }
938              
939 108 100       234 if ($deltatype == -1) {
940             # No further improvement possible; max-cardinality optimum
941             # reached. Do a final delta update to make the optimum
942             # verifyable.
943 2         9 assert($maxcardinality);
944 2         9 $deltatype = 1;
945 2         5 $delta = $dualvar[0];
946 2         8 foreach (@dualvar[0 .. ($nvertex-1)]) {
947 8 100       23 $delta = $_ if ($_ < $delta);
948             }
949 2 50       8 $delta = 0 if ($delta < 0);
950             }
951              
952             # Update dual variables according to delta.
953 108         258 for (my $v = 0; $v < $nvertex; $v++) {
954 822 100       2047 if ($label[$inblossom[$v]] == 1) {
    100          
955             # S-vertex: 2*u = 2*u - 2*delta
956 465         1133 $dualvar[$v] -= $delta;
957             } elsif ($label[$inblossom[$v]] == 2) {
958             # T-vertex: 2*u = 2*u + 2*delta
959 95         265 $dualvar[$v] += $delta;
960             }
961             }
962 108         276 for (my $b = $nvertex; $b < 2*$nvertex; $b++) {
963 822 100 100     2739 if (defined($blossombase[$b]) && $blossomparent[$b] == -1) {
964 56 100       186 if ($label[$b] == 1) {
    100          
965             # top-level S-blossom: z = z + 2*delta
966 25         74 $dualvar[$b] += $delta;
967             } elsif ($label[$b] == 2) {
968             # top-level T-blossom: z = z - 2*delta
969 10         27 $dualvar[$b] -= $delta;
970             }
971             }
972             }
973              
974             # Take action at the point where minimum delta occurred.
975 108 50       220 DBG("delta$deltatype=$delta") if ($DBG);
976 108 100       319 if ($deltatype == 1) {
    100          
    100          
    50          
977             # No further improvement possible; optimum reached.
978 22         47 last;
979             } elsif ($deltatype == 2) {
980             # Use the least-slack edge to continue the search.
981 31         53 $allowedge[$deltaedge>>1] = 1;
982 31         46 my $v = $endpoint[$deltaedge];
983 31         91 assert($label[$inblossom[$v]] == 1);
984 31         164 push @queue, $v;
985             } elsif ($deltatype == 3) {
986             # Use the least-slack edge to continue the search.
987 49         73 $allowedge[$deltaedge>>1] = 1;
988 49         73 my $v = $endpoint[$deltaedge];
989 49         159 assert($label[$inblossom[$v]] == 1);
990 49 50       243 DBG("PUSH $v") if ($DBG);
991 49         137 push @queue, $v;
992             } elsif ($deltatype == 4) {
993             # Expand the least-z blossom.
994 6         19 expandblossom($deltablossom, 0);
995             }
996              
997             # End of a this substage.
998             }
999              
1000             # Stop when no more augmenting path can be found.
1001 91 100       197 last if (!$augmented);
1002              
1003             # End of a stage; expand all S-blossoms which have dualvar = 0.
1004 69         194 for (my $b = $nvertex; $b < 2*$nvertex; $b++) {
1005 535 100 100     1984 if (defined($blossombase[$b]) && $blossomparent[$b] == -1 &&
      100        
      100        
1006             $label[$b] == 1 && $dualvar[$b] == 0) {
1007 1         5 expandblossom($b, 1);
1008             }
1009             }
1010              
1011             }
1012              
1013             # Verify that we reached the optimum solution.
1014 22 100 66     126 verifyoptimum() if ($CHECK_OPTIMUM && $all_integer_weights);
1015              
1016             # Return %ret such that $ret[$v] is the vertex to which $v is paired.
1017 22         37 my %ret;
1018 22         82 for (my $v = 0; $v < $nvertex; $v++) {
1019 143 100       316 if ($mate[$v] != -1) {
1020 138         361 assert($endpoint[$mate[$endpoint[$mate[$v]]]] == $v);
1021 138         906 $ret{$nodelist[$v]} = $nodelist[$endpoint[$mate[$v]]];
1022             }
1023             }
1024              
1025 22         67 undef @nodelist;
1026 22         69 undef %nodemap;
1027 22         79 undef @endpoint;
1028 22         75 undef @neighbend;
1029 22         34 undef @mate;
1030 22         43 undef @label;
1031 22         35 undef @labelend;
1032 22         34 undef @inblossom;
1033 22         37 undef @blossomparent;
1034 22         47 undef @blossomchilds;
1035 22         37 undef @blossombase;
1036 22         37 undef @blossomendps;
1037              
1038 22         3442 return %ret;
1039             }
1040              
1041              
1042             sub edges_from_Graph {
1043 0     0 1   my ($g) = @_;
1044 0           assert(!$g->is_multi_graph, "Graph must not be a multigraph");
1045 0           assert($g->is_undirected, "Graph must be undirected");
1046 0           my @edges;
1047 0           foreach ($g->edges) {
1048 0           assert($#{$_} == 1);
  0            
1049 0           my ($v, $w) = @{$_};
  0            
1050 0           assert($v ne $w, "Graph must not contain self loops");
1051 0           my $weight = $g->get_edge_weight($v, $w);
1052 0 0         $weight = 1 if (!defined($weight));
1053 0           push @edges, [ $v, $w, $weight ];
1054             }
1055 0           return \@edges;
1056             }
1057              
1058             1; # End of Graph::Matching