File Coverage

blib/lib/Vote/Count/Method/IRV.pm
Criterion Covered Total %
statement 59 59 100.0
branch 6 8 75.0
condition n/a
subroutine 12 12 100.0
pod 0 1 0.0
total 77 80 96.2


line stmt bran cond sub pod time code
1 1     1   658 use strict;
  1         3  
  1         32  
2 1     1   5 use warnings;
  1         2  
  1         38  
3 1     1   43 use 5.022;
  1         4  
4 1     1   5 use feature qw /postderef signatures/;
  1         1  
  1         153  
5              
6             package Vote::Count::Method::IRV;
7              
8 1     1   8 use namespace::autoclean;
  1         2  
  1         10  
9 1     1   81 use Moose;
  1         8  
  1         8  
10             extends 'Vote::Count';
11             # Brings the main Vote::Count Object in along with
12             # Topcount and other methods.
13             # with 'Vote::Count';
14             # with 'Vote::Count::Matrix';
15              
16             our $VERSION='0.007';
17              
18 1     1   6446 no warnings 'experimental';
  1         2  
  1         46  
19 1     1   6 use List::Util qw( min max );
  1         2  
  1         92  
20              
21             # use Vote::Count::RankCount;
22             # use Try::Tiny;
23 1     1   7 use TextTableTiny 'generate_markdown_table';
  1         1  
  1         49  
24 1     1   14 use Data::Printer;
  1         2  
  1         17  
25 1     1   49 use Data::Dumper;
  1         1  
  1         473  
26              
27             # use YAML::XS;
28              
29 3     3 0 8737 sub RunIRV ( $self, $active = undef ) {
  3         10  
  3         6  
  3         6  
30 3 50       15 unless ( defined $active ) {
31 3         138 $active = $self->BallotSet->{'choices'};
32             }
33 3         7 my $roundctr = 0;
34 3         6 my $maxround = scalar( keys %{$active} );
  3         11  
35             $self->logt( "Instant Runoff Voting",
36 3         9 'Choices: ', join( ', ', ( sort keys %{$active} ) ) );
  3         49  
37             # forever loop normally ends with return from $majority
38             # a tie should be detected and also generate a
39             # return from the else loop.
40             # if something goes wrong roundcountr/maxround
41             # will generate exception.
42             IRVLOOP:
43 3         8 until ( 0 ) {
44 16         23 $roundctr++;
45 16 50       36 die "IRVLOOP infinite stopped at $roundctr" if $roundctr > $maxround;
46 16         46 my $round = $self->TopCount($active);
47 16         56 $self->logv( '---', "IRV Round $roundctr", $round->RankTable() );
48 16         77 my $majority = $self->EvaluateTopCountMajority( $round );
49 16 100       34 if ( defined $majority->{'winner'} ) {
50 2         17 return $majority;
51             } else {
52 14         39 my @bottom = sort $round->ArrayBottom()->@*;
53 14 100       23 if ( scalar(@bottom) == scalar( keys %{$active} ) ) {
  14         31  
54             # if there is a tie at the end, the finalists should
55             # be both top and bottom and the active set.
56 1         6 $self->logt( "Tied: " . join( ', ', @bottom ) );
57 1         15 return { tie => 1, tied => \@bottom, winner => 0 };
58             }
59 13         50 $self->logv( "Eliminating: " . join( ', ', @bottom ) );
60 13         28 for my $b (@bottom) {
61 22         99 delete $active->{$b};
62             }
63             }
64             }
65             }
66              
67             1;
68              
69             #buildpod
70              
71             =pod
72              
73             =head1 IRV
74              
75             Some things to know about IRV.
76              
77              
78             =head2 Warning
79              
80             IRV is the best algorithm for resolving a small Condorcet Tie, but
81             a poor algorithm for an election. But it is really simple.
82              
83             =cut
84              
85             #buildpod