line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
39
|
|
|
39
|
|
27243
|
use strict; |
|
39
|
|
|
|
|
106
|
|
|
39
|
|
|
|
|
1249
|
|
2
|
39
|
|
|
39
|
|
214
|
use warnings; |
|
39
|
|
|
|
|
196
|
|
|
39
|
|
|
|
|
1018
|
|
3
|
39
|
|
|
39
|
|
688
|
use 5.024; |
|
39
|
|
|
|
|
146
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
use Moose::Role; |
6
|
39
|
|
|
39
|
|
228
|
|
|
39
|
|
|
|
|
88
|
|
|
39
|
|
|
|
|
370
|
|
7
|
|
|
|
|
|
|
use feature qw /postderef signatures/; |
8
|
39
|
|
|
39
|
|
226529
|
no warnings 'experimental'; |
|
39
|
|
|
|
|
109
|
|
|
39
|
|
|
|
|
3979
|
|
9
|
39
|
|
|
39
|
|
277
|
|
|
39
|
|
|
|
|
78
|
|
|
39
|
|
|
|
|
2086
|
|
10
|
|
|
|
|
|
|
use Storable 3.15 'dclone'; |
11
|
39
|
|
|
39
|
|
272
|
use Path::Tiny; |
|
39
|
|
|
|
|
650
|
|
|
39
|
|
|
|
|
2079
|
|
12
|
39
|
|
|
39
|
|
269
|
|
|
39
|
|
|
|
|
88
|
|
|
39
|
|
|
|
|
50164
|
|
13
|
|
|
|
|
|
|
# ABSTRACT: Role shared by Count and Matrix for common functionality. See Vote::Count Documentation. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION='2.02'; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 NAME |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Vote::Count::Common |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 VERSION 2.02 |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 Synopsis |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
This Role is consumed by Vote::Count and Vote::Count::Matrix. It provides common methods for the Active Set. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=cut |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
has 'BallotSet' => ( is => 'ro', isa => 'HashRef', required => 1 ); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
has 'Active' => ( |
32
|
|
|
|
|
|
|
is => 'ro', |
33
|
|
|
|
|
|
|
isa => 'HashRef', |
34
|
|
|
|
|
|
|
lazy => 1, |
35
|
|
|
|
|
|
|
builder => '_defaultactive', |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has 'VoteValue' => ( |
39
|
|
|
|
|
|
|
is => 'ro', |
40
|
|
|
|
|
|
|
isa => 'Int', |
41
|
|
|
|
|
|
|
default => 1, |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
has 'WithdrawalList' => ( |
45
|
|
|
|
|
|
|
is => 'rw', |
46
|
|
|
|
|
|
|
isa => 'Str', |
47
|
|
|
|
|
|
|
required => 0, |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
has 'PairMatrix' => ( |
51
|
|
|
|
|
|
|
is => 'ro', |
52
|
|
|
|
|
|
|
isa => 'Object', |
53
|
|
|
|
|
|
|
lazy => 1, |
54
|
|
|
|
|
|
|
builder => '_buildmatrix', |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my $tiebreak = |
58
|
58
|
|
|
58
|
|
106
|
defined( $self->TieBreakMethod() ) |
|
58
|
|
|
|
|
93
|
|
|
58
|
|
|
|
|
109
|
|
59
|
58
|
100
|
|
|
|
1598
|
? $self->TieBreakMethod() |
60
|
|
|
|
|
|
|
: 'none'; |
61
|
|
|
|
|
|
|
my %args = ( |
62
|
|
|
|
|
|
|
BallotSet => $self->BallotSet(), |
63
|
58
|
|
|
|
|
1449
|
Active => $self->Active(), |
64
|
|
|
|
|
|
|
TieBreakMethod => $tiebreak, |
65
|
|
|
|
|
|
|
LogTo => $self->LogTo() . '_matrix', |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
$args{'PrecedenceFile'} = $self->PrecedenceFile() if $self->PrecedenceFile(); |
68
|
|
|
|
|
|
|
$args{'TieBreakerFallBackPrecedence'} = $self->TieBreakerFallBackPrecedence(); |
69
|
58
|
100
|
|
|
|
1616
|
return Vote::Count::Matrix->new( %args ); |
70
|
58
|
|
|
|
|
1652
|
} |
71
|
58
|
|
|
|
|
1819
|
|
72
|
|
|
|
|
|
|
$self->{'PairMatrix'} = $self->_buildmatrix(); |
73
|
|
|
|
|
|
|
} |
74
|
3
|
|
|
3
|
1
|
13
|
|
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
6
|
|
75
|
3
|
|
|
|
|
9
|
return sort keys( $self->BallotSet()->{'choices'}->%* ); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
60
|
|
|
60
|
0
|
7981
|
my $active = dclone $self->BallotSet()->{'choices'} ; |
|
60
|
|
|
|
|
106
|
|
|
60
|
|
|
|
|
98
|
|
79
|
60
|
|
|
|
|
1813
|
if ( $self->WithdrawalList ) { |
80
|
|
|
|
|
|
|
for my $w (path( $self->WithdrawalList )->lines({ chomp => 1})) { |
81
|
|
|
|
|
|
|
delete $active->{$w}; |
82
|
154
|
|
|
154
|
|
284
|
} |
|
154
|
|
|
|
|
282
|
|
|
154
|
|
|
|
|
229
|
|
83
|
154
|
|
|
|
|
4102
|
} |
84
|
154
|
100
|
|
|
|
5121
|
return $active; |
85
|
2
|
|
|
|
|
47
|
} |
86
|
8
|
|
|
|
|
459
|
|
87
|
|
|
|
|
|
|
# Force deref |
88
|
|
|
|
|
|
|
$self->{'Active'} = dclone $active; |
89
|
154
|
|
|
|
|
3770
|
# if there is a child PairMatrix, update it too. |
90
|
|
|
|
|
|
|
if ( defined $self->{'PairMatrix'} ) { |
91
|
|
|
|
|
|
|
$self->{'PairMatrix'}{'Active'} = $self->{'Active'}; |
92
|
35
|
|
|
35
|
1
|
3384
|
} |
|
35
|
|
|
|
|
72
|
|
|
35
|
|
|
|
|
64
|
|
|
35
|
|
|
|
|
70
|
|
93
|
|
|
|
|
|
|
} |
94
|
35
|
|
|
|
|
1458
|
|
95
|
|
|
|
|
|
|
$self->{'Active'} = $self->_defaultactive(); |
96
|
35
|
100
|
|
|
|
214
|
} |
97
|
8
|
|
|
|
|
38
|
|
98
|
|
|
|
|
|
|
# I was typing the equivalent too often. made a method. |
99
|
|
|
|
|
|
|
$self->SetActive( { map { $_ => 1 } $active->@* } ); |
100
|
|
|
|
|
|
|
} |
101
|
1
|
|
|
1
|
1
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
102
|
1
|
|
|
|
|
4
|
# Force deref |
103
|
|
|
|
|
|
|
my $active = $self->Active(); |
104
|
|
|
|
|
|
|
return dclone $active; |
105
|
|
|
|
|
|
|
} |
106
|
7
|
|
|
7
|
1
|
435
|
|
|
7
|
|
|
|
|
18
|
|
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
13
|
|
107
|
7
|
|
|
|
|
22
|
# this deref also happens a lot |
|
29
|
|
|
|
|
90
|
|
108
|
|
|
|
|
|
|
return ( sort( keys( $self->Active->%* ) ) ); |
109
|
|
|
|
|
|
|
} |
110
|
231
|
|
|
231
|
1
|
436
|
|
|
231
|
|
|
|
|
429
|
|
|
231
|
|
|
|
|
357
|
|
111
|
|
|
|
|
|
|
delete $self->{'Active'}{$choice}; |
112
|
231
|
|
|
|
|
8285
|
} |
113
|
231
|
|
|
|
|
6929
|
|
114
|
|
|
|
|
|
|
return $self->BallotSet()->{'votescast'}; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
206
|
|
|
206
|
1
|
775
|
unless ( $self->BallotSet()->{'options'}{'rcv'} ) { |
|
206
|
|
|
|
|
344
|
|
|
206
|
|
|
|
|
310
|
|
118
|
206
|
|
|
|
|
5562
|
die "VotesActive Method only supports rcv"; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
my $set = $self->BallotSet(); |
121
|
13
|
|
|
13
|
1
|
3843
|
my $active = $self->Active(); |
|
13
|
|
|
|
|
22
|
|
|
13
|
|
|
|
|
18
|
|
|
13
|
|
|
|
|
18
|
|
122
|
13
|
|
|
|
|
40
|
my $activeCount = 0; |
123
|
|
|
|
|
|
|
LOOPVOTESACTIVE: |
124
|
|
|
|
|
|
|
for my $B ( values $set->{ballots}->%* ) { |
125
|
44
|
|
|
44
|
1
|
111
|
for my $V ( $B->{'votes'}->@* ) { |
|
44
|
|
|
|
|
70
|
|
|
44
|
|
|
|
|
70
|
|
126
|
44
|
|
|
|
|
1200
|
if ( defined $active->{$V} ) { |
127
|
|
|
|
|
|
|
$activeCount += $B->{'count'}; |
128
|
|
|
|
|
|
|
next LOOPVOTESACTIVE; |
129
|
6
|
|
|
6
|
1
|
13
|
} |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
10
|
|
130
|
6
|
50
|
|
|
|
189
|
} |
131
|
0
|
|
|
|
|
0
|
} |
132
|
|
|
|
|
|
|
return $activeCount; |
133
|
6
|
|
|
|
|
147
|
} |
134
|
6
|
|
|
|
|
158
|
|
135
|
6
|
|
|
|
|
15
|
if ( $self->BallotSet()->{'options'}{'rcv'} ) { |
136
|
|
|
|
|
|
|
return 'rcv'; |
137
|
6
|
|
|
|
|
24
|
} |
138
|
36
|
|
|
|
|
62
|
elsif ( $self->BallotSet()->{'options'}{'range'} ) { |
139
|
39
|
100
|
|
|
|
75
|
return 'range'; |
140
|
33
|
|
|
|
|
49
|
} |
141
|
33
|
|
|
|
|
54
|
else { |
142
|
|
|
|
|
|
|
die "BallotSetType is undefined or unknown type."; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
6
|
|
|
|
|
22
|
|
146
|
|
|
|
|
|
|
return $self->BallotSet()->{'ballots'}; |
147
|
|
|
|
|
|
|
} |
148
|
48
|
|
|
48
|
0
|
1216
|
|
|
48
|
|
|
|
|
80
|
|
|
48
|
|
|
|
|
81
|
|
149
|
48
|
100
|
|
|
|
1150
|
1; |
|
|
100
|
|
|
|
|
|
150
|
42
|
|
|
|
|
230
|
|
151
|
|
|
|
|
|
|
=head1 Usage |
152
|
|
|
|
|
|
|
|
153
|
5
|
|
|
|
|
31
|
This role is consumed by Vote::Count and Vote::Count::Matrix, providing a common set of functions to all Vote::Count objects. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 new |
156
|
1
|
|
|
|
|
11
|
|
157
|
|
|
|
|
|
|
The only required parameter is BallotSet. The BallotSet is provided by L<Vote::Count::ReadBallots>, you may place the BallotSet in a variable or more typically read it from within the new method. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
use Vote::Count; |
160
|
96
|
|
|
96
|
0
|
3379
|
use Vote::Count::ReadBallots; |
|
96
|
|
|
|
|
192
|
|
|
96
|
|
|
|
|
144
|
|
161
|
96
|
|
|
|
|
2596
|
my $Election = Vote::Count->new( BallotSet => read_ballots( $ballotfile ) ); |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 Optional Paramters to Vote::Count |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 Active |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Sets the Active Set at creation. See L<Active Sets>. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 VoteValue |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Sets a VoteValue for use in weighted systems like STV. The default value is 1. Approval and TopCount are aware of VoteValue for RCV ballots. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head2 LogTo |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Sets a path and Naming pattern for writing logs with the WriteLogs method. If LogTo is not provided the default location is I</tmp/votecount>. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
'LogTo' => '/logging_path/election_name' |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
See L<Vote::Count::Log> for more informationand and additional log path options. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head1 Logging Methods |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Vote::Count writes 3 logs: B<t>erse/brief, B<v>erbose, and B<d>etail. The three logging methods I<logt>, I<logv>, and I<logd> are used to record messages to those respective logs. The WriteLogs method is used to write the logs to disk. |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
For more detail, see L<Vote::Count::Log>. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 Active Sets |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Active sets are a Hash Reference where the keys represent the active choices and the value is true. The VoteCount Object contains an Active Set which can be Accessed via the Active() method which will return a reference to the Active Set (changing the reference will change the active set). The GetActive and SetActive methods break the reference links. GetActiveList returns the Active Set as a sorted list. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Many Components will take an argument for $activeset or default to the current Active set of the Vote::Count object, which is defaulted to the Choices defined in the BallotSet. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head2 Active |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Get Active Set as HashRef to the active set. Changing the new HashRef will change the internal Active Set, GetActive is often preferable as it will return a HashRef that is a copy instead. Active may be used as an optional parameter to L<new|"Optional Paramters to Vote::Count">. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head2 GetActive |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Returns a hashref containing a copy of the Active Set. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 GetActiveList |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Returns a simple array of the members of the Active Set. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head2 ResetActive |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Sets the Active Set to the full choices list of the BallotSet. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head2 SetActive |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head2 SetActiveFromArrayRef |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Same as SetActive except it takes an ArrayRef of the choices to be set as Active. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 Vote::Count Methods |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Most of these are provided by the Role Common and available directly in both Matrix objects and Vote::Count Objects. Vote::Count objects create a child Matrix object: PairMatrix. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 BallotSet |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Get BallotSet |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head2 PairMatrix |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Get a Matrix Object for the Active Set. Generated and cached on the first request. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 UpdatePairMatrix |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Regenerate and cache Matrix with current Active Set. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 VotesCast |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Returns the number of votes cast. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head2 VotesActive |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Returns the number of non-exhausted ballots based on the current Active Set. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 new |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Has the following Attributes: |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head2 WithdrawalList |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
A text file containing choices 1 per line that are withdrawn. Use when a choice may be included in the ballots but should be treated as not-present. Removing a choice from the choices list in a Ballot File will generate an exception from ReadBallots if it appears on any Ballots. Withdrawing a choice will exclude it from the Active Set if it is present in the Ballots. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=head2 Choices |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
Returns an array of all of the Choices in the Ballot Set. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 GetActiveList |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Returns a simple array of the members of the Active Set. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head2 ResetActive |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
Sets the Active Set to the full choices list of the BallotSet. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head2 SetActive |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Sets the Active Set to provided HashRef. The values to the hashref should evaluate as True. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head2 SetActiveFromArrayRef |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
Same as SetActive except it takes an ArrayRef of the choices to be set as Active. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head2 Defeat |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Remove $choice from current Active List. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
$Election->Defeat( $choice ); |
274
|
|
|
|
|
|
|
$Election->logv( "Defeated $choice"); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=cut |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#FOOTER |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=pod |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
BUG TRACKER |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
L<https://github.com/brainbuz/Vote-Count/issues> |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
AUTHOR |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
John Karr (BRAINBUZ) brainbuz@cpan.org |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
CONTRIBUTORS |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Copyright 2019-2021 by John Karr (BRAINBUZ) brainbuz@cpan.org. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
LICENSE |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
This module is released under the GNU Public License Version 3. See license file for details. For more information on this license visit L<http://fsf.org>. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
SUPPORT |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
This software is provided as is, per the terms of the GNU Public License. Professional support and customisation services are available from the author. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=cut |
303
|
|
|
|
|
|
|
|