File Coverage

blib/lib/Algorithm/Pair/Best.pm
Criterion Covered Total %
statement 194 240 80.8
branch 61 108 56.4
condition 12 30 40.0
subroutine 17 22 77.2
pod 16 19 84.2
total 300 419 71.6


line stmt bran cond sub pod time code
1             # $Id$
2              
3             # Algorithm::Pair::Best.pm
4             #
5             # Copyright (C) 2004, 2005 Reid Augustin reid@HelloSix.com
6             #
7             # This library is free software; you can redistribute it and/or modify it
8             # under the same terms as Perl itself, either Perl version 5.8.5 or, at your
9             # option, any later version of Perl 5 you may have available.
10             #
11             # This program is distributed in the hope that it will be useful, but
12             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13             # or FITNESS FOR A PARTICULAR PURPOSE.
14             #
15              
16              
17             # first, some boilerplate:
18 1     1   38928 use strict;
  1         2  
  1         58  
19             require 5.001;
20              
21              
22             # an Algorithm::Pair::Best is a pairing object. it is one member of a linked list of
23             # Algorithm::Pair::Best's. The first Algorithm::Pair::Best in the list is
24             # a bit different - it's the root and it has some higher-level control
25             # functions. The root is not itself a pairing item. Items to be paired
26             # are 'add'ed to the root Algorithm::Pair::Best object.
27             package Algorithm::Pair::Best;
28 1     1   5 use Carp;
  1         2  
  1         3047  
29              
30             our @ISA = qw(Exporter);
31              
32             # Items to export into callers namespace by default. Note: do not export
33             # names by default without a very good reason. Use EXPORT_OK instead.
34             # Do not simply export all your public functions/methods/constants.
35              
36             # This allows declaration use PackageName ':all';
37             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
38             # will save memory.
39             our %EXPORT_TAGS = ( 'all' => [ qw(
40             ) ] );
41              
42             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
43              
44             our @EXPORT = qw(
45             );
46              
47             our $VERSION = '1.036'; # VERSION
48              
49             # ABSTRACT: deprecated - use Algorithm::Pair::Best2
50              
51             # uncomment the following line if perl -d is giving you recursion warnings:
52             # $DB::deep = 1000; # potentially deep recursion here
53              
54             #
55             # Class Variables
56             #
57              
58             my $state = 'init'; # current state
59             my @items = (); # the items to pair
60             my $bestScore = -999999; # current best score of all attempts to date
61             my @bestPairs = (); # pairing array that yeilded the bestScore
62             my $currScore; # score of current pairing attempt
63             my @currPairs = (); # pairing array of current attempt
64             my $window = 5; # pick 5 pairs by default - should finish fairly quickly
65             my $negOnly = 1; # for 'negatives scores only' optimization
66             my $scoreSubs = [ sub { croak "No scoreSubs defined"; } ]; # suitability subroutines used to score candidates
67             # a hash with the names and default values for object data
68             my %fields = (
69             # class variables common to the whole list of Algorithm::Pair::Best:
70             state => \$state,
71             items => \@items,
72             bestScore => \$bestScore,
73             bestPairs => \@bestPairs,
74             currScore => \$currScore,
75             currPairs => \@currPairs,
76             window => \$window,
77             negOnly => \$negOnly,
78             scoreSubs => \$scoreSubs,
79             # normal object data
80             # info => {}, # user info (ref to empty hash)
81             # citems => [], # candidate items, sorted by suitability
82             # cscores => {}, # scores for each candidate
83             opp => undef, # the guy we're paired against, or undef if none
84             next => undef, # the next player in the list, or undef if at the end
85             );
86              
87             ######################################################
88             #
89             # Public methods
90             #
91             #####################################################
92              
93              
94             sub new {
95 9     9 1 33 my ($proto, %args) = @_;
96              
97 9         56 my $my = { %fields }; # copy of default fields
98 9         22 $my->{info} = {}; # user info
99 9         18 $my->{citems} = []; # candidate items, sorted by suitability
100 9         14 $my->{cscores} = {}; # cache of candidate scores
101 9   33     35 bless($my, ref($proto) || $proto);
102             # transfer user args
103 9         16 foreach my $a (keys(%args)) {
104 9 50 33     55 if ($a eq 'state') {
    50 33        
    50 0        
    50 0        
    50          
    50          
    100          
    50          
105 0         0 $my->state($args{$a});
106             } elsif ($a eq 'items') {
107 0         0 $my->items(@{$args{$a}});
  0         0  
108             } elsif ($a eq 'bestScore') {
109 0         0 $my->bestScore($args{$a});
110             } elsif ($a eq 'bestPairs') {
111 0         0 $my->bestPairs(@{$args{$a}});
  0         0  
112             } elsif ($a eq 'window') {
113 0         0 $my->window($args{$a});
114             } elsif ($a eq 'negOnly') {
115 0         0 $my->negOnly($args{$a});
116             } elsif ($a eq 'scoreSubs') {
117 1         4 $my->scoreSubs($args{$a});
118             } elsif (($a eq 'info') or
119             ($a eq 'citems') or
120             ($a eq 'cscores') or
121             ($a eq 'opp') or
122             ($a eq 'next')) {
123 8         19 $my->{$a} = $args{$a};
124             } else {
125 0         0 croak "$a is not a legal option to Algorithm::Pair::Best->new";
126             }
127             }
128 9         21 return $my;
129             }
130              
131              
132             # accessor methods for class variables
133 11 100   11 0 12 sub state {my $my = shift; ${$my->{state}} = shift if (@_); return ${$my->{state}} ;}
  11         21  
  10         15  
  11         12  
  11         19  
134 0 0   0 1 0 sub items {my $my = shift; @{$my->{items}} = @_ if (@_); return @{$my->{items}} ;}
  0         0  
  0         0  
  0         0  
  0         0  
135 0 0   0 0 0 sub bestPairs {my $my = shift; @{$my->{bestPairs}} = @_ if (@_); return @{$my->{bestPairs}};}
  0         0  
  0         0  
  0         0  
  0         0  
136 2 100   2 1 667 sub bestScore {my $my = shift; ${$my->{bestScore}} = shift if (@_); return ${$my->{bestScore}};}
  2         7  
  1         2  
  2         3  
  2         6  
137 1 50   1 0 2 sub currScore {my $my = shift; ${$my->{currScore}} = shift if (@_); return ${$my->{currScore}};}
  1         2  
  1         2  
  1         2  
  1         1  
138 0 0   0 1 0 sub window {my $my = shift; ${$my->{window}} = shift if (@_); return ${$my->{window}} ;}
  0         0  
  0         0  
  0         0  
  0         0  
139 0 0   0 1 0 sub negOnly {my $my = shift; ${$my->{negOnly}} = shift if (@_); return ${$my->{negOnly}} ;}
  0         0  
  0         0  
  0         0  
  0         0  
140 37 100   37 1 29 sub scoreSubs {my $my = shift; ${$my->{scoreSubs}} = shift if (@_); return ${$my->{scoreSubs}};}
  37         56  
  1         7  
  37         33  
  37         77  
141             # accessor methods for object data
142 0 0   0 1 0 sub info {my $my = shift; $my->{info} = shift if (@_); return $my->{info} ;}
  0         0  
  0         0  
143 500 100   500 1 471 sub citems {my $my = shift; $my->{citems} = shift if (@_); return $my->{citems} ;}
  500         714  
  500         1081  
144 72 50   72 1 65 sub cscores {my $my = shift; $my->{cscores} = shift if (@_); return $my->{cscores} ;}
  72         101  
  72         150  
145 452 100   452 1 442 sub opp {my $my = shift; $my->{opp} = shift if (@_); return $my->{opp} ;}
  452         726  
  452         1110  
146 75 100   75 1 93 sub next {my $my = shift; $my->{next} = shift if (@_); return $my->{next} ;}
  75         119  
  75         202  
147              
148              
149             sub add {
150 8     8 1 861 my $my = shift;
151              
152 8         14 $my->state('add');
153 8         8 my @items;
154 8         13 foreach my $item (@_) {
155 8         18 my $pairItem = Algorithm::Pair::Best->new(info => $item);
156 8 100       17 if (exists($my->{lastItem})) {
157 7         13 $my->{lastItem}->next($pairItem); # link new item into chain
158             }
159 8         12 $my->{lastItem} = $pairItem; # set new last item
160 8         9 push(@items, $pairItem);
161 8         7 push(@{$my->{items}}, $pairItem);
  8         13  
162 8 100       13 $my->next($pairItem) unless (defined($my->next));
163             }
164 8 50       17 if (@items > 1) {
165 0 0       0 return wantarray ? @items : \@items;
166             }
167 8         16 return $items[0];
168             }
169              
170              
171             sub score {
172 316     316 1 297 my ($my, $candidate, $new_score) = @_;
173              
174 316 50       435 if (defined($new_score)) {
175 0         0 $my->cscores->{$candidate} = $new_score; # cache it
176 0         0 $candidate->cscores->{$my} = $new_score; # cache his too
177             }
178 316 100       1052 return($my->{cscores}{$candidate}) if (defined($my->{cscores}{$candidate}));
179 36         33 my $score = 0;
180 36         25 foreach (@{$my->scoreSubs}) {
  36         56  
181 36         62 $score += $my->$_($candidate);
182             }
183 36         367 $my->cscores->{$candidate} = $score; # cache it
184 36         49 $candidate->cscores->{$my} = $score; # cache his while we're at it
185 36         90 return $score;
186             }
187              
188              
189              
190             sub sortCandidates {
191 1     1 1 2 my ($my) = @_;
192              
193 1         2 foreach my $item (@{$my->{items}}) {
  1         2  
194 8         9 my @citems = sort( { $item->score($b) <=> $item->score($a) } @{$my->{items}});
  116         172  
  8         18  
195 8         18 $item->citems(\@citems);
196 8         9 foreach my $cs (values(%{$item->{cscore}})) {
  8         30  
197 0 0       0 ${$my->{negOnly}} = 0 if ($cs > 0);
  0         0  
198             }
199             }
200 1         2 $my->state('sort');
201             }
202              
203              
204             sub pick {
205 1     1 1 8 my ($my, $window) = @_;
206              
207 1 50       2 $window = $my->window unless(defined($window)); # size of sliding window
208 1         2 my (@pairs, %sanity);
209 1         1 my $alreadyPaired = 0;
210 1         2 my $notPaired = 0;
211 1         2 while (@pairs < @{$my->{items}}) {
  2         10  
212 1         3 my $top = $my->wpick($window); # pick top pairs
213 1         2 my $save = 1;
214 1 50 33     1 if (((@{$top} + @pairs) >= @{$my->{items}}) or
  1         2  
  1         11  
  0         0  
215             (@{$top} < 2 * $window)) {
216 1         1 $save = @{$top} / 2; # done - empty the list
  1         3  
217             }
218 1         4 while ($save--) {
219 4         5 my $p1 = shift @{$top};
  4         5  
220 4         4 my $p2 = shift @{$top};
  4         5  
221 4 50       17 $my->progress($p1, $p2) if (defined(&progress));
222 4         19 $p1->opp($p2); # take these two out of contention
223 4         6 $p2->opp($p1);
224 4         6 push (@pairs, $p1, $p2);
225 4 50       43 $alreadyPaired++ if (exists($sanity{$p1}));
226 4 50       9 $alreadyPaired++ if (exists($sanity{$p2}));
227 4         7 $sanity{$p1} = $p2; # yeah, I know we 'can't usefully use
228 4         14 $sanity{$p2} = $p1; # refs as hash keys', but we
229             # don't need the ref back here,
230             # just need a unique key
231             }
232             }
233 1         2 foreach (@{$my->{items}}) {
  1         2  
234 8 50       15 $notPaired++ unless (exists($sanity{$_}));
235 8         16 delete($sanity{$_});
236             }
237 1         3 my $msg = '';
238 1 50       3 $msg .= "$alreadyPaired ITEMS ALREADY PAIRED!\n" if($alreadyPaired);
239 1 50       3 $msg .= "$notPaired ITEMS NOT PAIRED!\n" if($notPaired);
240 1 50       4 $msg .= scalar(keys(%sanity)) . " ITEMS EXTRA!\n" if(scalar(keys(%sanity)));
241 1 50       3 croak "$msg" unless ($msg eq '');
242 1 50       7 return wantarray ? @pairs : \@pairs;
243             }
244              
245              
246              
247             sub wpick {
248 1     1 1 16 my ($my, $window) = @_;
249              
250 1 50       3 unless($my->state eq 'pick') {
251 1         4 $my->sortCandidates;
252             }
253 1         3 $my->state('pick');
254 1         2 my $avail = 0;
255 1         2 foreach my $p (@{$my->{items}}) {
  1         1  
256 8 50       14 next if (defined($p->opp)); # skip if already paired
257 8 100       12 $my = $p if($avail == 0); # make my be first available
258 8         9 $avail++;
259 8 100       21 last if ($avail >= $window * 2);
260             }
261 1 50       3 if ($avail <= 1) {
262 0 0       0 if ($avail == 1) {
263 0         0 carp "Can't pick 1 - returning empty pairing list (last player will be left out)";
264             }
265 0         0 return ([]);
266             }
267 1 50       5 if ($avail % 2) {
268 0         0 $avail--;
269 0         0 carp "Can't pick from an odd number - last player will be left out";
270             }
271              
272 1         2 $avail /= 2;
273 1 50       2 if ($avail < $window) {
274 0         0 carp "Not enough candidates: reducing maxPair to $avail";
275             }
276              
277 1         4 $my->bestScore(-999999);
278 1         1 @{$my->{bestPairs}} = ();
  1         2  
279 1         4 $my->currScore(0);
280 1         2 @{$my->{currPairs}} = ();
  1         2  
281             # kick off recursive pairing
282 1         2 $my->_rpick($my->next, $avail, 0); # starting candidate is my next, and depth is 0
283 1 50       4 if ($my->{oddError}) { # shouldn't be possible
284 0         0 carp STDERR "Warning: odd number, last player not paired!\n"
285             }
286 1         3 return($my->{bestPairs});
287             }
288              
289              
290             sub _rpick {
291 32     32   43 my ($my, $firstCandidate, $window, $deep) = @_;
292              
293             # number of candidates to try to pair with - any more
294             # just eats time without improving the quality of the pairing
295 32         39 my $maxCand = (2 * $window) - 1;
296 32         32 push(@{$my->{currPairs}}, $my); # put myself on the pairing list
  32         40  
297 32         36 my $cIdx = 0;
298 32         39 my $candidate;
299 32         74 for (my $ii = 0; $ii < $maxCand; $ii++) {
300 204         325 do {
301 204         302 $candidate = $my->citems->[$cIdx++];
302 84   100     85 } while (($cIdx <= scalar(@{$my->citems})) and
      33        
303             (defined($candidate->opp) or # find next unpaired in candidate list
304             ($candidate == $my))); # make sure it's not me!
305 84 50       94 last unless ($cIdx <= scalar(@{$my->citems}));
  84         132  
306 84         137 my $cscore = $my->score($candidate);
307             # call callers scoreFunc if defined
308 84 50       153 $cscore = $my->scoreFunc($candidate, $cscore) if(defined(&scoreFunc));
309 84         92 ${$my->{currScore}} += $cscore; # add opp's score to total
  84         114  
310 84 100 66     83 if (${$my->{negOnly}} and (${$my->{currScore}} < ${$my->{bestScore}})) {
  84         171  
  84         98  
  84         220  
311             # we're below best, and it can only get worse, skip!
312             } else {
313 37         61 $candidate->opp($my); # pair him with me
314 37         51 $my->opp($candidate); # and me with him
315 37         33 push(@{$my->{currPairs}}, $candidate); # put this opp on the pairing list
  37         58  
316 37 100       50 if ($window > 1) {
317 31         33 my $next = $my;
318 31   66     83 while (defined($next) and defined($next->opp)) {
319 58         81 $next = $next->next;
320             }
321 31 50       56 if (defined($next)) {
322 31         73 $next->_rpick($firstCandidate, $window - 1, $deep + 1);
323             } else {
324 0         0 carp "Out of candidates too soon!"; # shouldn't happen
325             }
326             } else {
327             # choose best of previous or current:
328 6 100       7 if (${$my->{currScore}} > ${$my->{bestScore}}) {
  6         7  
  6         13  
329 5         5 ${$my->{bestScore}} = ${$my->{currScore}};
  5         6  
  5         6  
330 5         6 @{$my->{bestPairs}} = ();
  5         9  
331 5         6 @{$my->{bestPairs}} = @{$my->{currPairs}};
  5         10  
  5         6  
332             }
333             }
334 37         86 pop(@{$my->{currPairs}}); # remove opp from pairing list
  37         49  
335 37         63 $candidate->opp(undef); # break pairing with this guy
336             }
337 84         87 ${$my->{currScore}} -= $cscore; # remove opp's score to total
  84         196  
338             }
339 32         32 pop(@{$my->{currPairs}}); # remove me from current list
  32         37  
340 32         58 $my->opp(undef); # I ain't got nobody...
341 32         47 return;
342             }
343              
344             1;
345              
346              
347              
348             =pod
349              
350             =head1 NAME
351              
352             Algorithm::Pair::Best - deprecated - use Algorithm::Pair::Best2
353              
354             =head1 VERSION
355              
356             version 1.036
357              
358             =head1 SYNOPSIS
359              
360             use Algorithm::Pair::Best;
361              
362             my $pair = Algorithm::Pair::Best->new( ? options ? );
363              
364             $pair->add( item, ? item, ... ? );
365              
366             @pairList = $pair->pick( ? $window ? );
367              
368             =head1 DESCRIPTION
369              
370             Given a set of user-supplied scoring functions that compare all possible
371             pairs of items, Algorithm::Pair::Best attempts to find the 'best'
372             collective pairings of the entire group of items.
373              
374             After creating an Algorithm::Pair::Best-EB object, B a list of
375             items (players) to be paired. B connects the new items into a linked
376             list. The total number of items Bed to the linked list must consist
377             of an even number of items or you'll get an error when you try to B
378             the pairs.
379              
380             Pairings are determined partially by the original order items were added,
381             but more importantly, items are paired based on scores which are determined
382             by user supplied functions that provide a score for each item in relation
383             to other items (see B below). An B hash is attached to
384             each itme to assist the scoring functions. It may be convenient to add
385             access methods to the Algorithm::Pair::Best package from the main namespace
386             (see the scoreSubs option to B below for an example).
387              
388             Algorithm::Pair::Best-EB explores all combinations of items and
389             returns the pairing with the best (highest) score. This can be an expensive
390             proposition - the number of combinations goes up very fast with respect to the
391             number of items:
392              
393             items combinations
394             2 1 (1)
395             4 3 (1 * 3)
396             6 15 (1 * 3 * 5)
397             8 105 (1 * 3 * 5 * 7)
398             10 945 (1 * 3 * 5 * 7 * 9
399             12 10395 (1 * 3 * 5 * 7 * 9 * 11)
400             14 135135 (1 * 3 * 5 * 7 * 9 * 11 * 13)
401              
402             It is clearly unreasonable to try to pair a significant number of items. On
403             my system it takes about 2 seconds to pair 12 items (6 pairs), and 20 seconds
404             to pair 14 items (with no 'negative scores only' optimization). Trying to
405             completely pair even 30 items would take too long.
406              
407             Fortunately, there is a way to get pretty good results for large numbers, even
408             if they're not perfect. Instead of trying to pair the whole list at once,
409             Algorithm::Pair::Best-EB pairs a series of smaller groups within
410             a 'window' to get good 'local' results. The list created by B should
411             be moderately sorted so that most reasonable candidates will be within
412             window range of each other.
413              
414             The B method accepts a B option to limit the number of pairs
415             in each window. The B option can also be overridden by calling
416             B with an explicit window argument:
417              
418             $pair->pick($window);
419              
420             See the description of the B and B below.
421              
422             =head1 NAME
423              
424             Algorithm::Pair::Best is deprecated - use Algorithm::Pair::Best2
425              
426             Algorithm::Pair::Best - Perl module to select pairings (designed for Go
427             tournaments, but can be used for anything, really).
428              
429             =head1 METHODS
430              
431             =over 4
432              
433             =item my $pair = Bnew>(?options?)
434              
435             A B Algorithm::Pair::Best object becomes the root of a linked list of
436             Algorithm::Pair::Best objects. This root does not represent an item to be
437             paired. It's just a control point for the collection of items to be paired.
438              
439             Items are added to the Algorithm::Pair::Best list with the method (see
440             below).
441              
442             =back
443              
444             =head2 Options
445              
446             =over 4
447              
448             =item B => number of pairs
449              
450             Sets the default number of pairs in the sliding pairing window during a
451             B. Can also be set by passing a B argument to B.
452              
453             Here's how a window value of 5 (pairs) works: first pair items 1 through 10.
454             Keep the pairing for the top two items and then pair items 2 through 12. Keep
455             the top pairing and move down to items 4 through 14. Keep sliding the window
456             down until we reach the last 10 items (which are completed in one iteration).
457             In this way, a tournament with 60 players takes less than 1/4 a minute (again,
458             on my system) to pair with very good results. See the B script in
459             B for a working example.
460              
461             Default: 5
462              
463             =item B => true or false
464              
465             Enable/disable the 'negative scores only" optimization. If any score greater
466             than 0 is found during B, Algorithm::Pair::Best turns this
467             flag off.
468              
469             IMPORTANT: If this flag is turned on and a scoreSub can return a number greater
470             than 0, the resultant pairing may not be optimal, even locally.
471              
472             Default: 1 (enabled)
473              
474             =item B => reference to array of scoring subroutines
475              
476             Scoring subroutines are called in array order as:
477              
478             foreach my $s (@{$my->scoreSubs}) {
479             $score += $my->$s($candidate);
480             }
481              
482             Scores are accumulated and pairings are attempted. The pairing with the
483             highest cumulative score is kept as the 'best'. Note: Algorithm::Pair::Best
484             works best with scoring subroutines that return only scores less than or equal
485             to 0 - see the B method for more details.
486              
487             The scoring subroutines should be symmetric so that:
488              
489             $a->$scoreSub($b) == $b->$scoreSub($a)
490              
491             Example:
492              
493             Note that the scores below are negative (Algorithm::Pair::Best searches for
494             the highest combined score). 'Negative scores only' allows an optimization
495             that is probably worth keeping in mind - it can reduce pairing time by several
496             orders of magnitude (or allow a larger B). See the B
497             method for more information.
498              
499             . . .
500             # create an array of scoring subroutines:
501             our @scoreSubs = (
502             sub { # difference in rating.
503             my ($my, $candidate, $explain) = @_;
504              
505             # the multiplier here is 1, so that makes this the 'normal' factor
506             my $score = -(abs($my->rating - $candidate->rating));
507             return sprintf "rating:%5.1f", $score if ($explain);
508             return $score;
509             },
510             sub { # already played?
511             my ($my, $candidate, $explain) = @_;
512              
513             my $already = 0;
514             foreach (@{$my->{info}{played}}) {
515             $already++ if ($_ == $candidate); # we might have played him several times!
516             }
517             # large penalty for each time we've already played
518             my $score = -16 * $already;
519             return sprintf "played:%3.0f", $score if ($explain);
520             return $score;
521             },
522             );
523              
524             # the 'difference in rating' scoring subroutine above needs a 'rating'
525             # accessor method in the Algorithm::Pair::Best namespace:
526             {
527             package Algorithm::Pair::Best;
528             sub rating { # add method to access ratings (used in scoreSubs above)
529             my $my = shift;
530              
531             $my->{info}{rating} = shift if (@_);
532             return $my->{info}{rating};
533             }
534             }
535             # back to the main namespace
536             . . .
537              
538             In the above example, note that there is an extra optional B<$explain>
539             argument. Algorithm::Pair::Best never sets that argument, but user code can
540             include:
541              
542             my @reasons;
543             foreach my $sSub (@scoreSubs) {
544             push(@reasons, $p1->$sSub($p2, 1)); # explain scoring
545             }
546             printf "%8s vs %-8s %s\n", $id1, $id2, join(', ', @reasons);
547              
548             to explain how $p1 scores when paired with $p2.
549              
550             Default: ref to empty array
551              
552             =back
553              
554             =head2 Accessor Methods
555              
556             Accessor methods can read and write the following items:
557              
558             =over 4
559              
560             =item B reference to the list of Bed items (root only)
561              
562             =item B reference to the user-defined info hash
563              
564             =item B reference to the hash of scores cache
565              
566             =item B reference to list of candidates sorted by score
567              
568             =item B currently selected opponent, or undef if not paired
569              
570             =item B next candidate in the list
571              
572             =item B (class) default number of pairs in sliding window
573              
574             =item B (class) use 'negative scores only' optimization
575              
576             =item B (class) user-supplied list of scoring subroutines
577              
578             =item B (class) current best score for all pairings to date
579              
580             =back
581              
582             Accessor methods set the appropriate variable if called with a parameter, and
583             return the current (or new) value.
584              
585             =head2 Other methods
586              
587             =over
588              
589             =item @pair_items = $pair-EB ( item [ item ...] )
590              
591             Add an item (or several items) to be paired. The item(s) can be any scalar,
592             but it's most useful if it is a reference to a hash that contains some kind of
593             ID and information (like rating and previous opponents) that can be used to
594             B this item relative to the other items.
595              
596             If a single item is added, the return value is a reference to the
597             Algorithm::Pair::Best object created for the item (regardless of calling
598             context).
599              
600             If multiple items are added, the return value is the list of created
601             Algorithm::Pair::Best objects in array context, and a reference to the list in
602             scalar context.
603              
604             Note: the returned pair_items list is not very useful since they have not yet
605             been paired.
606              
607             =item $pair-EB ( candidate, ?new_score? )
608              
609             Returns the score (as calculated by calling the list of user-supplied
610             scoreSubs) of the current pairing item relative to the candidate pairing item.
611              
612             The score is calculated only once, and the cached value is returned
613             thereafter.
614              
615             If new_score is defined, the cached candidate and item scores are
616             set to new_score.
617              
618             =item $pair-EB
619              
620             Sort each candidate list for each item. This method calls B
621             (above) which caches the score for each candidate in each item.
622              
623             Normally this routine does not need to be called as the B method calls
624             B before it starts picking. However, if you would like to modify
625             candidate scores based on the sorting itself (for example, in the early rounds
626             of a tournament, you may wish to avoid pairing the best matches against each
627             other), you can call B, and then make scoring adjustments (use
628             the B method to get a reference to the sorted list of candidates, then
629             use $item-EB($candidate, $new_score) to change the score). After
630             changing the score cache, calling the B method calls B
631             once more which will re-sort based on the new scores cache.
632              
633             Note: during B, the scores are checked for non-negative
634             values. If only 0 or negative values are used, the B method can
635             optimize by skipping branches that already score below the current best
636             pairing. Any scores greater than 0 disable the 'negative scores only'
637             (B) optimization.
638              
639             =item @pairs = $pair-EB ( ?$window? )
640              
641             Returns the best pairing found using the sliding window technique (calling
642             B) as discussed in DESCRIPTION above. The size of the window is
643             B<$windows> pairs (2*$windows items). If no window argument is passed, the
644             default window selected in the B call is used.
645              
646             B returns the list (or a reference to the list in scalar context) of
647             Algorithm::Pair::Best objects in pairing order: item[0] is paired to item[1],
648             item[2] to item[3], etc.
649              
650             B performs a sanity check on the pairs list, checking that no item is
651             paired twice, and that all items are paired.
652              
653             =item $pair-EB ( $item0, $item1 )
654              
655             Each time a pair is finalized in the B routine above, it checks to see
656             if a subroutine called B has been defined. If so, B calls
657             $pair->B($item0, $item1) where $item0 and $item1 are the most
658             recently added pair of items.
659              
660             B is not defined in the Algorithm::Pair::Best package. It is meant
661             to be provided by the caller. For example, to print a message as each pair is
662             finalized:
663              
664             . . .
665             {
666             package Algorithm::Pair::Best;
667             sub progress {
668             my ($my, $item0, $item1) = @_;
669              
670             # assuming you have provided an 'id' method that returns a string:
671             print $item0->id, " paired with ", $item1->id, "\n";
672             }
673             }
674              
675             # back to main:: namespace
676             . . .
677              
678             =item $pairsRef = $pair-EB ( $window )
679              
680             Normally B is only called by the B method.
681              
682             B returns a reference to a list of the best pairing of B<$window> pairs
683             (or 2*B<$window> items) starting from the first unpaired item in the list (as
684             determined by B order). The returned list is in pairing order as
685             described in B.
686              
687             If there are fewer than 2*B<$window> items remaining to be paired, prints an
688             error and returns the best pairing for the remaining items. If an odd number
689             of items remain, prints an error and returns the best pairing excluding the
690             last item.
691              
692             Note that while the pairing starts from the first item in the B list, the
693             returned pairs list may contain items from outside the first 2*B<$window> items
694             in the B list. This is because each item has its own ordered list of
695             preferred pairs. However, the first unpaired item in the B list will be
696             the first item in the returned list.
697              
698             Similarly, in the 'odd number of items remaining' situation, the discarded
699             item is not neccessarily the last item in the B list.
700              
701             =item $score = $pair-EB ( $candidate, $score )
702              
703             B is not defined in the Algorithm::Pair::Best package, but the
704             B method checks to see if the caller has defined a subroutine by that
705             name. If defined, it is called each time a candidate score is added to the
706             B total for a trial pairing.
707              
708             Normally, Algorithm::Pair::Best simply adds the scores and tries for the
709             highest total score. Some pairings may work better with a different total
710             score, for example the sum of the squares of the scores (to reduce the ability
711             of one bad pairing to compensate for a group of good pairings). B
712             provides a hook for this modification.
713              
714             If defined, scoreFunc is called as:
715              
716             $score = $item->scoreFunc($candidate, $score);
717              
718             where $item is the current Algorithm::Pair::Best item being paired, $candidate
719             is the current candidate item under consideration, and $score is $candidate's
720             unaltered score (wrt $item).
721              
722             IMPORTANT: Remember to retain negative scores (or disable the B
723             optimization.
724              
725             Example use of B:
726             . . .
727             {
728             package Algorithm::Pair::Best;
729             sub scoreFunc {
730             my ($my, $candidate, $score) = @_;
731              
732             # we want to minimize the squares of the scores:
733             return -($score * $score);
734             }
735             }
736              
737             # back to main:: namespace
738             . . .
739              
740             =back
741              
742             =head1 SEE ALSO
743              
744             =over
745              
746             =item gopair(1)
747              
748             The B script from the Games::Go::GoPair package uses
749             Algorithm::Pair::Best to run pairings for a go tournament
750              
751             =back
752              
753             =head1 AUTHOR
754              
755             Reid Augustin, Ereid@HelloSix.comE
756              
757             =head1 COPYRIGHT AND LICENSE
758              
759             Copyright (C) 2004, 2005 by Reid Augustin
760              
761             This library is free software; you can redistribute it and/or modify
762             it under the same terms as Perl itself, either Perl version 5.8.5 or,
763             at your option, any later version of Perl 5 you may have available.
764              
765             =head1 AUTHOR
766              
767             Reid Augustin
768              
769             =head1 COPYRIGHT AND LICENSE
770              
771             This software is copyright (c) 2011 by Reid Augustin.
772              
773             This is free software; you can redistribute it and/or modify it under
774             the same terms as the Perl 5 programming language system itself.
775              
776             =cut
777              
778              
779             __END__