Title: | Election Vote Counting with Safety Features |
---|---|
Description: | Fork of 'vote_2.3-2', Raftery et al. (2021) <DOI:10.32614/RJ-2021-086>, with additional support for stochastic experimentation. |
Authors: | Clark Thomborson [cre, aut] |
Maintainer: | Clark Thomborson <[email protected]> |
License: | GPL (>= 2) |
Version: | 1.0.1 |
Built: | 2024-12-05 07:10:25 UTC |
Source: | CRAN |
.print method for summary object
.print.summary.SafeVote(x, ...)
.print.summary.SafeVote(x, ...)
x , ...
|
undocumented |
undocumented
summarises vote-totals for subsequent printing
.summary.SafeVote(object, larger.wins = TRUE, reorder = TRUE)
.summary.SafeVote(object, larger.wins = TRUE, reorder = TRUE)
object |
vector of total votes per candidate |
larger.wins |
TRUE if candidates are "voted in" rather than voted-out |
reorder |
TRUE if output data.frame columns should be in rank-order |
a data.frame with three columns and nc+1 rows, where nc is the number of candidates. The first column contains candidate names and a final entry named "Sum". The second column contains vote totals. The third column is a vector of chars which indicate whether the candidate has been elected. The data.frame has four named attributes carrying election parameters.
TODO: refactor into a modern dialect of R, perhaps by defining a constructor for an election_info S3 object with a summary method and a print method
This data is one of 87 sets of ballots from the Tideman data collection, as curated by The Center for Range Voting.
This set of ballots was collected in 1987 by Nicolaus Tideman, with support from NSF grant SES86-18328. "The data are records of ballots from elections of British organizations (mostly trade unions using PR-STV or IRV voting) in which the voters ranked the candidates. The data were gathered under a stipulation that the organizations involved would remain anonymous."
The ballots were encoded in David Hill's format, and have been converted to the preference-vector format of this package. The archival file A4.HIL at rangevoting.org contains eight blank ballot papers (1, 616, 619, 620, 685, 686, 687, 688) which we have retained. This set may be counted by 'stv(a3_hil,nseats=attr(a3_hil,"nseats"))'.
data(a3_hil)
data(a3_hil)
A data frame with attribute "nseats" = 7, consisting of 989 observations and 15 candidates.
This data is one of 87 sets of ballots from the Tideman data collection, as curated by The Center for Range Voting. The ballots were archived in David Hill's format, and have been converted to the preference-vector format of this package.
This set of ballots was collected in 1987 by Nicolaus Tideman, with support from NSF grant SES86-18328. "The data are records of ballots from elections of British organizations (mostly trade unions using PR-STV or IRV voting) in which the voters ranked the candidates. The data were gathered under a stipulation that the organizations involved would remain anonymous."
data(a4_hil)
data(a4_hil)
A data frame with attribute "nseats" = 2, consisting of 43 observations and 14 candidates.
This data is one of 87 sets of ballots from the Tideman data collection, as curated by The Center for Range Voting.
This set of ballots was collected in 1988 by Nicolaus Tideman, with support from NSF grant SES86-18328. "The data are records of ballots from elections of British organizations (mostly trade unions using PR-STV or IRV voting) in which the voters ranked the candidates. The data were gathered under a stipulation that the organizations involved would remain anonymous."
The ballots were encoded in David Hill's format, and have been converted to the preference-vector format of this package. Candidates have been renamed to letters of the alphabet, for ease of comparison with Table 3 of Tideman (2000). Note: the DOI for this article is 10.1023/A:1005082925477, with an embedded colon which isn't handled by the usual DOI-to-URL conversions.
As noted in this table, it is a very close race between candidates D, F, and B in the final rounds of a Meek count of 'a53_hil'.
Tideman's implementation of Meek's method excludes B (on 59.02 votes), then elects D in the final round (on 88.33 votes) with a margin of 0.95 votes ahead of F (on 87.38 votes).
In v1.0, 'stv(a53.hil,quota.hare=TRUE)' excludes F (on 56.418 votes), then elects D in the final round (on 79.705 votes) with a winning margin of 0.747 votes ahead of B (on 78.958 votes). The result of the election is the same but the vote counts and winning margins differ significantly; so we conclude that 'stv(quota.hare=TRUE)' in SafeVote v1.0 is not a reliable proxy for Tideman's implementation of Meek's algorithm.
Future researchers may wish to adjust the quota calculation of 'vote.stv()' so that it is no longer biased upward by a "fuzz" of 0.001, to see if this change significantly reduces the discrepancies with Tideman's implementation of Meek.
It would be unreasonable to expect an exact replication of results from two different implementations of an STV method. We leave it to future researchers to develop a formal specification, so that it would be possible to verify the correctness of an implementation. We also leave it to future researchers to develop a set of test cases with appropriate levels of tolerance for the vagaries of floating-point roundoff in optimised (or even unoptimised!) compilations of the same code on different computing systems. We suggest that 'a53_hil' be included in any such test set.
We note in passing that B.A. Wichmann, in "Checking two STV programs", Voting Matters 11, 2000, discussed the cross-validation exercise he conducted between the ERBS implementation of its voting rules and the Church of England's implementation of its voting rules. In both cases, he discovered ambiguities in the specification as well as defects in the implementation.
data(a53_hil)
data(a53_hil)
A data frame with attribute "nseats" = 4, consisting of 460 observations and 10 candidates.
See https://arxiv.org/abs/2102.05801
approval(votes, nseats = 1, fsep = "\t", quiet = FALSE, ...)
approval(votes, nseats = 1, fsep = "\t", quiet = FALSE, ...)
votes , nseats , fsep , quiet , ...
|
undocumented |
undocumented
as.SafeRankExpt()
as.SafeRankExpt(df)
as.SafeRankExpt(df)
df |
data.frame object |
a SafeRankExpt object, or stop() if df fails some sanity checks
undocumented internal method
assemble.args.for.check.score(x, max.score = NULL, ...)
assemble.args.for.check.score(x, max.score = NULL, ...)
x , max.score , ...
|
undocumented |
undocumented
undocumented internal method
assemble.args.for.check.stv(x, equal.ranking = FALSE, ...)
assemble.args.for.check.stv(x, equal.ranking = FALSE, ...)
x , equal.ranking , ...
|
undocumented |
undocumented
Undocumented internal method
backwards.tiebreak(prefs, icans, elim = TRUE)
backwards.tiebreak(prefs, icans, elim = TRUE)
prefs |
undocumented |
icans |
undocumented |
elim |
undocumented |
parameter-checking method for nseats (internal)
check.nseats( nseats = NULL, ncandidates, default = 1, mcan = NULL, complete.ranking = FALSE )
check.nseats( nseats = NULL, ncandidates, default = 1, mcan = NULL, complete.ranking = FALSE )
nseats |
initially-specified number of seats to be filled in an election |
ncandidates |
the number of candidates standing for election |
default |
the return value of this function when nseats=NULL |
mcan |
a deprecated name for nseats |
complete.ranking |
when TRUE, the return value is in 1..ncandidates When FALSE, the return value is in 1..ncandidates-1 (for backwards compatibility) |
a valid non-NULL value for the number of seats to be filled
check the validity of a partial ranking
check.ranking(r)
check.ranking(r)
r |
a numeric vector |
a partial ranking of the elements of 'r', using 'ties.method="min"'
undocumented internal method
check.votes(x, ..., quiet = FALSE)
check.votes(x, ..., quiet = FALSE)
x , quiet , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.approval(record, ...)
check.votes.approval(record, ...)
record , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.condorcet(record, ...)
check.votes.condorcet(record, ...)
record , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.plurality(record, ...)
check.votes.plurality(record, ...)
record , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.score(record, max.score, ...)
check.votes.score(record, max.score, ...)
record , max.score , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.stv(record, equal.ranking = FALSE, ...)
check.votes.stv(record, equal.ranking = FALSE, ...)
record , equal.ranking , ...
|
undocumented |
undocumented
undocumented internal method
check.votes.tworound.runoff(record, ...)
check.votes.tworound.runoff(record, ...)
record , ...
|
undocumented |
undocumented
the least upper bound on a pair of rankings
combineRankings(r1, r2)
combineRankings(r1, r2)
r1 , r2
|
numeric vectors |
the most complete (but possibly partial) ranking which is consistent with both r1 and r2. Uses 'ties.method="min"'
combineRankings( c(3,1,2), c(2,1,3) )
combineRankings( c(3,1,2), c(2,1,3) )
internal method to analyse the partial results of an stv() ballot count, to discover a complete ranking of all candidates. The ranking may depend on the value of nseats, because this affects how votes are transferred.
completeRankingTable(object, quiet, verbose)
completeRankingTable(object, quiet, verbose)
object |
partial results |
quiet |
TRUE to suppress console output |
verbose |
TRUE to produce diagnostic output |
data.frame with columns TotalRank, Margin, Candidate, Elected, SafeRank
The Condorcet method elects the candidate who wins a majority of the ranked vote in every head to head election against each of the other candidates. A Condorcet winner is a candidate who beats all other candidates in pairwise comparisons. Analogously, a Condorcet loser is a candidate who loses against all other candidates. Neither Condorcet winner nor loser might exist.
condorcet( votes, runoff = FALSE, nseats = 1, safety = 1, fsep = "\t", quiet = FALSE, ... )
condorcet( votes, runoff = FALSE, nseats = 1, safety = 1, fsep = "\t", quiet = FALSE, ... )
votes |
A matrix or data.frame containing the votes. Rows correspond to the votes, columns correspond to the candidates. If 'votes' is a character string, it is interpreted as a file name from which the votes are to be read. See below. |
runoff |
Logical. If TRUE and no Condorcet winner exists, the election goes into a run-off, see below. |
nseats |
the number of seats to be filled in this election |
safety |
Parameter for a clustering heuristic on a total ranking of the candidates. Conjecture: the default of '1.0' ensures a separation of one s.d. between clusters, when 'votes' are i.u.d. permutations on the candidates. |
fsep |
If 'votes' is a file name, this argument gives the column separator in the file. |
quiet |
If TRUE no output is printed. |
... |
Undocumented intent (preserved from legacy code) |
If the runoff argument is set to 'TRUE' and no Condorcet winner exists, two or more candidates with the most pairwise wins are selected and the method is applied to such subset. If more than two candidates are in such run-off, the selection is performed repeatedly, until either a winner is selected or no more selection is possible.
The input data votes is structured the same way as for the stv method: Row 'i' contains the preferences of voter 'i' numbered '1; 2; : : : ; r; 0; 0; 0; 0', in some order, while equal preferences are allowed. The columns correspond to the candidates. The dimnames of the columns are the names of the candidates; if these are not supplied then the candidates are lettered 'A, B, C, ...'. If the dataset contains missing values (NA), they are replaced by zeros.
If a ballot has equally-ranked candidates, its rankings are tested for
validity: for each preference which does not have any duplicate,
there are exactly
preferences
with
. If
any ballot 'x' fails this validity test, it is automatically corrected (aka
"converted") into a valid ballot using 'x <- rank(x, ties.method = "min")',
and a warning is issued.
This method also computes a Borda ranking of all candidates, using
tournament-style scoring. This ranking is "fuzzed" into a 'safeRank', with
approximately 1 s.d. of fuzz when 'safety=1.0' and voter preferences are
i.u.d. A warning is thrown if a 'safeRank' violates the (extended) Condorcet
principle: that Candidate is more highly ranked than Candidate
only if a majority of voters agree with this.
Object of class 'SafeVote.condorcet'
{ data(food_election) condorcet(food_election) }
{ data(food_election) condorcet(food_election) }
The 'correct.ranking' function returns a modified set of ballots. Its argument 'partial' determines if ballots are partially set to '0' ('TRUE'), or if it is a complete re-ranking, as allowed when 'equal.ranking = TRUE'. It can be used by calling it explicitly. It is called by 'stv' if 'equal.ranking = TRUE' or 'invalid.partial = TRUE'. It is also called from within the 'condorcet' function with the default value ('FALSE') for 'partial', i.e. interpreting any '0' as a last= preference.
correct.ranking(votes, partial = FALSE, quiet = FALSE)
correct.ranking(votes, partial = FALSE, quiet = FALSE)
votes |
original contents of ballot box |
partial |
if 'FALSE' (default), each ballot is interpreted, if possible, as a complete (but not necessarily total) ranking of the candidates. If 'TRUE', a ballot will contain a '0' on unranked candidates. |
quiet |
suppress diagnostics |
corrected ballots
Dataset containing ranked votes for the Dublin West constituency in 2002, Ireland.
data(dublin_west)
data(dublin_west)
A data frame with 29988 observations and 9 candidates. Each record corresponds to one ballot with candidates being ranked between 1 and 9 with zeros allowed.
prints the basic results of an election
election.info(x)
election.info(x)
x |
basic election results, as named attributes of an R structure or object |
data.frame : an invisible copy of the printed results
TODO: refactor into a modern dialect of R, e.g. defining a constructor for an election_info S3 object with a print method
extract margins from the results of a ballot count
extractMargins(marginNames, crRanks, cr)
extractMargins(marginNames, crRanks, cr)
marginNames |
list of colnames of the margins in our SafeRank result |
crRanks |
ranks of candidates, not necessarily total |
cr |
structure returned by a ballot-counting method Margins are adjusted for tied candidates, such that candidates within a tie group have margins indicative of their relative strengths. Extremely small margins are indicative of floating-point roundoff errors. |
named list of margins
Extract a ranking vector by name from the results of a ballot count
extractRank(rankMethod, cr)
extractRank(rankMethod, cr)
rankMethod |
"safeRank", "elected", or "rank" |
cr |
structure returned by a ballot-counting method |
a numeric ranking vector, in order of colnames(cr$data)
Sample data for testing SafeVote
data(food_election)
data(food_election)
A data frame with 20 observations and 5 candidates (Oranges, Pears, Chocolate, Strawberries, Sweets). Each record corresponds to one ballot with ranking for each of the candidates.
Undocumented internal method
forwards.tiebreak(prefs, icans, elim = TRUE)
forwards.tiebreak(prefs, icans, elim = TRUE)
prefs |
undocumented |
icans |
undocumented |
elim |
undocumented |
The image function visualizes the joint distribution of two preferences (if 'all.pref=FALSE') given 'xpref' and 'ypref', as well as the marginal distribution of all preferences (if 'all.pref=TRUE'). The joint distribution can be shown as proportions (if 'proportion=TRUE') or raw vote counts (if 'proportion=FALSE').
## S3 method for class 'SafeVote.condorcet' image(x, ...)
## S3 method for class 'SafeVote.condorcet' image(x, ...)
x |
object of type SafeVote.condorcet |
... |
See arguments for image.SafeVote.stv, especially 'xpref', 'ypref', 'all.pref' and 'proportion'. |
image object, with side-effect in RStudio Plots pane
visualisation of joint and marginal distributions in STV preferences
## S3 method for class 'SafeVote.stv' image(x, xpref = 2, ypref = 1, all.pref = FALSE, proportion = TRUE, ...)
## S3 method for class 'SafeVote.stv' image(x, xpref = 2, ypref = 1, all.pref = FALSE, proportion = TRUE, ...)
x |
STV results to be visualised |
xpref , ypref
|
candidates shown in a joint distribution plot |
all.pref |
plot the joint distribution of two preferences (if 'all.pref=FALSE') or the marginal distribution of all preferences (if 'all.pref=TRUE'). |
proportion |
The joint distribution can be shown either as proportions (if 'proportion=TRUE') or raw vote counts (if 'proportion=FALSE'). |
... |
args passed to fields::image.plot() |
image object, with side-effect in RStudio Plots pane
Modified version of ims_election, for use in approval voting.
data(ims_approval)
data(ims_approval)
A data frame with 620 observations and 10 candidates (names were made up). Each record corresponds to one ballot, with 0 indicating disapproval of a candidate and 1 indicating approval.
Datasets containing anonymized votes for a past Council election of the Institute of Mathematical Statistics (IMS). The dataset ims_election is the original dataset used with single transferable vote, where candidate names have been changed.
data(ims_election)
data(ims_election)
A data frame with 620 observations and 10 candidates (names were made up). Each record corresponds to one ballot. The IMS Council voting is done using the STV method, and thus the ims_election dataset contains ballots with candidates being ranked between 1 and 10 with zeros allowed.
Modified version of ims_election, for use in plurality voting.
data(ims_plurality)
data(ims_plurality)
A data frame with 620 observations and 10 candidates (names were made up). Each record corresponds to one ballot, with 1 against the voter's most-preferred candidate and 0 against all other candidates.
Modified version of ims_election, for use in score voting.
data(ims_score)
data(ims_score)
A data frame with 620 observations and 10 candidates (names were made up). Each record corresponds to one ballot, with higher values indicating the more-preferred candidates.
Copy of ims_election, included for backwards compatibility.
data(ims_election)
data(ims_election)
A data frame with 620 observations and 10 candidates (names were made up). Each record corresponds to one ballot. The IMS Council voting is done using the STV method, and thus the ims_election dataset contains ballots with candidates being ranked between 1 and 10 with zeros allowed.
This method was added Jan 2022 – it was named in a warning message but had apparently either never been implemented, or had been "lost" through versioning.
invalid.votes(x)
invalid.votes(x)
x |
value returned by stv, condorcet, approval, plurality, or score |
matrix with one column per candidate and one row per invalid ballot
is.SafeRankExpt()
is.SafeRankExpt(x)
is.SafeRankExpt(x)
x |
object of unknown class |
TRUE if x is a valid SafeRankExpt object
undocumented internal method
is.valid.vote(x, method, ...)
is.valid.vote(x, method, ...)
x , method , ...
|
undocumented |
undocumented
Find a loser and their margin of victory
loserMargin(votes)
loserMargin(votes)
votes |
cleaned ballots |
length-2 vector: the index of a losing candidate, and their margin of loss (0 if a tie, NA if no winners)
Constructor for the results of a SafeRank experiment
new_SafeRankExpt( rankNames = list(), marginNames = list(), countMethod = character(0), rankMethod = character(0), datasetName = character(0), experimentalMethod = character(0), countArgs = list(), nseats = integer(0), otherFactors = list(), unitFactors = list() )
new_SafeRankExpt( rankNames = list(), marginNames = list(), countMethod = character(0), rankMethod = character(0), datasetName = character(0), experimentalMethod = character(0), countArgs = list(), nseats = integer(0), otherFactors = list(), unitFactors = list() )
rankNames |
colnames for per-candidate ranks |
marginNames |
colnames for per-candidate margins |
countMethod |
secondary factor: counting method e.g. "stv" |
rankMethod |
secondary factor: ranking method e.g. "elected" |
datasetName |
secondary factor: name of the dataset of ballots |
experimentalMethod |
secondary factor: name of the method which simulated these elections e.g. "testFraction" |
countArgs |
secondary factor: args passed to countMethod |
nseats |
secondary factor: number of seats to be filled |
otherFactors |
other secondary factors, e.g. parameters to experimentalMethod |
unitFactors |
per-unit factors derived from PRNG of the experimental harness, e.g describing the ballots randomly deleted during testDeletions |
object of class SafeRankExpt
Undocumented internal method
ordered.preferences(vmat)
ordered.preferences(vmat)
vmat |
undocumented |
Undocumented internal method
ordered.tiebreak(vmat, seed = NULL)
ordered.tiebreak(vmat, seed = NULL)
vmat |
undocumented |
seed |
undocumented |
The "adjusted rank" of a candidate is their ranking plus their
scaled "winning margin". The scaled margin is
, where
is the adjusted margin (i.e. the number
of votes by which this candidate is ahead of the next-weaker candidate,
adjusted for the number of ballots
and the number of seats
),
and
is the margin-scaling parameter 'cMargin'.
## S3 method for class 'SafeRankExpt' plot( x, facetWrap = FALSE, nResults = NA, anBallots = 0, cMargin = 1, xlab = "Ballots", ylab = "Adjusted Rank", title = NULL, subtitle = "(default)", line = TRUE, boxPlot = FALSE, boxPlotCutInterval = 10, pointSize = 1, ... )
## S3 method for class 'SafeRankExpt' plot( x, facetWrap = FALSE, nResults = NA, anBallots = 0, cMargin = 1, xlab = "Ballots", ylab = "Adjusted Rank", title = NULL, subtitle = "(default)", line = TRUE, boxPlot = FALSE, boxPlotCutInterval = 10, pointSize = 1, ... )
x |
object containing experimental results |
facetWrap |
TRUE provides per-candidate scatterplots |
nResults |
number of candidates whose results are plotted (omitting the least-favoured candidates first) |
anBallots , cMargin
|
parameters in the rank-adjustment formula |
xlab , ylab
|
axis labels |
title |
overall title for the plot. Default: NULL |
subtitle |
subtitle for the plot. Default: value of nSeats and any non-zero rank-adjustment parameters |
line |
TRUE will connect points with lines, and will disable jitter |
boxPlot |
TRUE for a boxplot, rather than the default xy-scatter |
boxPlotCutInterval |
parameter of boxplot, default 10 |
pointSize |
diameter of points |
... |
params for generic plot() |
The default value of 'cMargin=1.0' draws visual attention to candidates with
a very small winning margin, as their adjusted rank is very near to
. Candidates with anything more than a small winning margin have
only a small rank adjustment, due to the exponential scaling.
A scaling linear in is applied to margins when 'anBallots>0'. Such
a linear scaling may be a helpful way to visualise the winning margins in STV
elections because the margin of victory for an elected candidate is typically
not much larger than the quota of
(Droop) or
(Hare).
The linear scaling factor is
, where
is the value of
'anBallots',
is the number of seats, and
is the number of
ballots. For plotting on the (inverted) adjusted rank scale, the
linearly-scaled margin is added to the candidate's rank. Note that the
linearly-scaled margins are zero when
, and thus have no effect on
the adjusted rank. You might want to increase the value of 'anBallots',
starting from 1.0, until the winning candidate's adjusted rank is 1.0 when
all ballots are counted, then confirm that the adjusted ranks of other
candidates are still congruent with their ranking (i.e. that the
rank-adjustment is less than 1 in all cases except perhaps on an initial
transient with small numbers of ballots).
When both 'anBallots' and 'cMargins' are non-zero, the ranks are adjusted with both exponentially-scaled margins and linearly-scaled margins. The resulting plot would be difficult to interpret in a valid way.
Todo: Accept a list of SafeVoteExpt objects.
Todo: Multiple counts with the same number of ballots could be summarised with a box-and-whisker graphic, rather than a set of jittered points.
Todo: Consider developing a linear scaling that is appropriate for plotting stochastic experimental data derived from Condorcet elections.
graphics object, with side-effect in RStudio Plots pane
The 'plot' function shows the evolution of the total score for each candidate as well as the quota.
## S3 method for class 'SafeVote.stv' plot(x, xlab = "Count", ylab = "Preferences", point.size = 2, ...)
## S3 method for class 'SafeVote.stv' plot(x, xlab = "Count", ylab = "Preferences", point.size = 2, ...)
x |
stv results |
xlab , ylab
|
axis labels |
point.size |
diameter of elected/eliminated points |
... |
params for generic plot() |
graphics object, with side-effect in RStudio's Plots pane
See https://arxiv.org/abs/2102.05801
plurality(votes, nseats = 1, fsep = "\t", quiet = FALSE, ...)
plurality(votes, nseats = 1, fsep = "\t", quiet = FALSE, ...)
votes , nseats , fsep , quiet , ...
|
undocumented |
undocumented
Coerce input 'data' into a matrix
prepare.votes(data, fsep = "\n")
prepare.votes(data, fsep = "\n")
data |
possibly a .csv file, possibly an R object |
fsep |
separation character for .csv e.g. tab or comma |
a matrix with one row per ballot, one column per candidate, with named rows and columns
Print method for summary.SafeRankExpt
## S3 method for class 'summary.SafeRankExpt' print(x, ...)
## S3 method for class 'summary.SafeRankExpt' print(x, ...)
x |
experimental results |
... |
args for generic print() |
invisible(x), with side-effects to console
print method for summary object
## S3 method for class 'summary.SafeVote.approval' print(x, ...)
## S3 method for class 'summary.SafeVote.approval' print(x, ...)
x , ...
|
undocumented |
undocumented
print method for summary.SafeVote.condorcet
## S3 method for class 'summary.SafeVote.condorcet' print(x, ...)
## S3 method for class 'summary.SafeVote.condorcet' print(x, ...)
x |
object of type summary.SafeVote.condorcet |
... |
parameters passed to generic print |
textual description of 'x'
print method for summary of plurality object
## S3 method for class 'summary.SafeVote.plurality' print(x, ...)
## S3 method for class 'summary.SafeVote.plurality' print(x, ...)
x , ...
|
undocumented |
undocumented
print method for summary.score object
## S3 method for class 'summary.SafeVote.score' print(x, ...)
## S3 method for class 'summary.SafeVote.score' print(x, ...)
x , ...
|
undocumented |
undocumented
print() method for a summary() of a SafeVote result
## S3 method for class 'summary.SafeVote.stv' print(x, ...)
## S3 method for class 'summary.SafeVote.stv' print(x, ...)
x |
election results |
... |
args to be passed to kable() |
no return value, called for side-effect of printing to console
add a row to a SafeRankExpt object
rbind_SafeRankExpt(object, row)
rbind_SafeRankExpt(object, row)
object |
prior results of experimentation |
row |
new observations |
SafeRankExpt object with an additional row
rangevoting.org/TidemanData.html: The data are in a format developed by David Hill. The first line contains the number of candidates and the number to be elected. (Many but not all elections were multi-winner.) In subsequent lines that represent ballot papers, the first number is always 1. (The format was designed for a counting program that treats the first number as the number of instances of the ordering of the candidates on the line.) Next on these lines is a sequence of numbers representing a voter's reported ranking: The number of the candidate ranked first, the number of the candidate ranked second, and so on. The end of the reported ranking is signaled by a zero. A zero at the beginning of the ranking is a signal that the list of ballot papers has ended. Next come the names of the candidates, each in parentheses, as required by the counting program, and finally the name of the election.
readHil(filnm, quiet = FALSE)
readHil(filnm, quiet = FALSE)
filnm |
name of a file in .HIL format |
quiet |
suppress diagnostic output |
a matrix with one row per ballot, one column per candidate, with named rows and columns, and with attributes "nseats" and "ename"
Remove a candidate, amending ballot papers as required
remove.candidate(votes, can, quiet = TRUE)
remove.candidate(votes, can, quiet = TRUE)
votes |
ballot box |
can |
candidate to be removed |
quiet |
suppress diagnostics |
amended ballot box
See https://arxiv.org/abs/2102.05801
score( votes, nseats = 1, max.score = NULL, larger.wins = TRUE, fsep = "\t", quiet = FALSE, ... )
score( votes, nseats = 1, max.score = NULL, larger.wins = TRUE, fsep = "\t", quiet = FALSE, ... )
votes , nseats , max.score , larger.wins , fsep , quiet , ...
|
undocumented |
undocumented
Undocumented internal method, renamed from 'solve.tiebreak' to avoid confusion with generic solve()
solveTiebreak(method, prefs, icans, ordered.ranking = NULL, elim = TRUE)
solveTiebreak(method, prefs, icans, ordered.ranking = NULL, elim = TRUE)
method |
undocumented |
prefs |
undocumented |
icans |
undocumented |
ordered.ranking |
undocumented |
elim |
undocumented |
undocumented
The 'votes' parameter is as described in condorcet()
with the following
additional semantics.
stv( votes, nseats = NULL, eps = 0.001, equal.ranking = FALSE, fsep = "\t", ties = c("f", "b"), quota.hare = FALSE, constant.quota = FALSE, win.by.elim = TRUE, group.nseats = NULL, group.members = NULL, complete.ranking = FALSE, invalid.partial = FALSE, verbose = FALSE, seed = NULL, quiet = FALSE, digits = 3, backwards.compatible = FALSE, safety = 1, ... )
stv( votes, nseats = NULL, eps = 0.001, equal.ranking = FALSE, fsep = "\t", ties = c("f", "b"), quota.hare = FALSE, constant.quota = FALSE, win.by.elim = TRUE, group.nseats = NULL, group.members = NULL, complete.ranking = FALSE, invalid.partial = FALSE, verbose = FALSE, seed = NULL, quiet = FALSE, digits = 3, backwards.compatible = FALSE, safety = 1, ... )
votes |
an array with one column per candidate and one row per ballot,
as described in |
nseats |
the number of seats to be filled in this election |
eps |
fuzz-factor when comparing fractional votes. The default of 0.001 is preserved from the legacy code, injecting substantial validity hazards into the codebase. We have not attempted to mitigate any of these hazards in 'SafeVote v1.0.0'. We prefer instead to retain backwards-compatibility with the legacy code in 'vote_2.3-2' in the knowledge that, even if these hazards were adequately addressed, the resulting code is unlikely to be reliable at replicating the results of any other implementation of any of the many variants of "STV" counting methods. Please see the description of the 'a53_hil' dataset in this package for some preliminary findings on the magnitude of the vote-count-variances which may be injected by differing implementations of broadly-similar "STV" counting methods. |
equal.ranking |
if 'TRUE', equal preferences are allowed. |
fsep |
column-separator for output |
ties |
vector of tie-breaking methods: ”f” for forward, ”b” for backward |
quota.hare |
'TRUE' if Hare quota, 'FALSE' if Droop quota (default) |
constant.quota |
'TRUE' if quota is held constant. Over-rides 'quota.hare'. Default is 'FALSE' |
win.by.elim |
'TRUE' (default) if the quota is waived when there are no more candidates than vacant seats. Note: there is no lower limit when the quota is waived, so a candidate may be elected on zero votes. |
group.nseats |
number of seats reserved to members of a group |
group.members |
vector of members of the group with reserved seats |
complete.ranking |
is 'TRUE' by default. This parameter is retained
solely for backwards compatibility with |
invalid.partial |
'TRUE' if ballots which do not specify a complete ranking of candidates are informal (aka "invalid") i.e. ignored (with a warning). Default is 'FALSE'. |
verbose |
'TRUE' for diagnostic output |
seed |
integer seed for tie-breaking. Warning: if non-'NULL', the PRNG
for R is reseeded prior to every random tie-break among the
possibly-elected candidates. We have preserved this functionality in this
branch to allow regression against the legacy codebase of |
quiet |
'TRUE' to suppress console output |
digits |
number of significant digits in the output table |
backwards.compatible |
'TRUE' to regress against vote2_3.2 by disabling $margins, $fuzz, $rankingTable, $safeRank |
safety |
number of standard deviations on vote-counts, when producing a safeRank by clustering near-ties in a complete ranking |
... |
undocumented intent (preserved from legacy code) |
By default the preferences are not allowed to contain duplicates per ballot. However, if the argument 'equal.ranking' is set to 'TRUE', ballots are allowed to have the same ranking for multiple candidates. The desired format is such that for each preference $i$ that does not have any duplicate, there must be exactly $i – 1$ preferences $j$ with $0 < j < i$. For example, valid ordered preferences are '1; 1; 3; 4; …', or '1; 2; 3; 3; 3; 6; …', but NOT '1; 1; 2; 3; …', or NOT '1; 2; 3; 3; 3; 5; 6; …'. If the data contain such invalid votes, they are automatically corrected and a warning is issued by calling the 'correct.ranking' function.
If equal ranking is not allowed ('equal.ranking = FALSE'), the argument 'invalid.partial' can be used to make ballots containing duplicates or gaps partially valid. If it is 'TRUE', a ballot is considered valid up to a preference that is in normal case not allowed. For example, ballots '1; 2; 3; 4; 4; 6' or '1; 2; 3; 5; 6; 7' would be both converted into '1; 2; 3; 0; 0; 0', because the ballots contain valid ranking only up to the third preference.
By default, ties in the STV algorithm are resolved using the forwards tie-breaking method, see Newland and Briton (Section 5.2.5). Argument 'ties' can be set to ”b” in order to use the backwards tie-breaking method, see O’Neill (2004). In addition, both methods are complemented by the following “ordered” method: Prior to the STV election candidates are ordered by the number of first preferences. Equal ranks are resolved by moving to the number of second preferences, then third and so on. Remaining ties are broken by random draws. Such complete ordering is used to break any tie that cannot be resolved by the forwards or backwards method. If there is at least one tie during the processing, the output contains a row indicating in which count a tie-break happened (see the 'ties' element in the Value section for an explanation of the symbols).
The ordered tiebreaking described above can be analysed from outside of the 'stv' function by using the 'ordered.tiebreak' function for viewing the a-priori ordering (the highest number is the best and lowest is the worst). Such ranking is produced by comparing candidates along the columns of the matrix returned by 'ordered.preferences'.
object of class 'vote.stv'. Note: the winning margins in this object are valid for the elected candidates and their (total) ranking, but must be adjusted within tiegroups to be valid for the candidates' (possibly partial) safeRank.
data(food_election) stv(food_election, safety = 0.0) stv(food_election, nseats = 2)
data(food_election) stv(food_election, safety = 0.0) stv(food_election, nseats = 2)
summary method for SafeRankExpt
## S3 method for class 'SafeRankExpt' summary(object, ...)
## S3 method for class 'SafeRankExpt' summary(object, ...)
object |
experimental results to be summarised |
... |
args for generic summary() |
summary.SafeRankExpt object
summary method for approval results
## S3 method for class 'SafeVote.approval' summary(object, ...)
## S3 method for class 'SafeVote.approval' summary(object, ...)
object , ...
|
undocumented |
undocumented
Summary method for condorcet() results
## S3 method for class 'SafeVote.condorcet' summary(object, ...)
## S3 method for class 'SafeVote.condorcet' summary(object, ...)
object |
of type SafeVote.condorcet |
... |
undocumented, currently unused |
data.frame object
summary method for plurality object
## S3 method for class 'SafeVote.plurality' summary(object, ...)
## S3 method for class 'SafeVote.plurality' summary(object, ...)
object , ...
|
undocumented |
descriptive dataframe
summary method for score object
## S3 method for class 'SafeVote.score' summary(object, ...)
## S3 method for class 'SafeVote.score' summary(object, ...)
object , ...
|
undocumented |
undocumented
summary() method for a SafeVote result
## S3 method for class 'SafeVote.stv' summary(object, ..., digits = 3)
## S3 method for class 'SafeVote.stv' summary(object, ..., digits = 3)
object |
undocumented, legacy code |
... |
undocumented |
digits |
undocumented |
data.frame summarising 'object', for use by 'print' method
Renamed from 'sum.votes' to avoid confusion with the generic sum()
sumOfVotes(votes)
sumOfVotes(votes)
votes |
ballots are rows, candidates are columns |
vector of votes for each candidate
Ballots are added until a specified number of simulated elections ('arep') have been held. If a 'favoured' candidate is specified, then the ballot-box is stuffed with ballots awarding first-preference to this candidate. Alternatively, a 'tacticalBallot' may be specified. If both 'favoured' and 'tacticalBallot' are 'NULL', then a random candidate is selected as the favoured one.
testAdditions( votes, ainc = 1, arep = NULL, favoured = NULL, tacticalBallot = NULL, rankMethod = "safeRank", countMethod = "stv", countArgs = list(), exptName = NULL, equiet = FALSE, everbose = FALSE )
testAdditions( votes, ainc = 1, arep = NULL, favoured = NULL, tacticalBallot = NULL, rankMethod = "safeRank", countMethod = "stv", countArgs = list(), exptName = NULL, equiet = FALSE, everbose = FALSE )
votes |
A set of ballots, as in vote_2.3.2 |
ainc |
Number of ballots to be added in each step |
arep |
Maximum number of ballot-stuffed elections to run |
favoured |
Name of the candidate being "plumped". If 'NULL', a random candidate is selected from among the candidates not initially top-ranked. All other candidates are fully-ranked at random, with an identical ballot paper being stuffed multiple times. An integer value for 'favoured' is interpreted as an index into the candidate names. |
tacticalBallot |
A ballot paper i.e. a vector of length 'ncol(ballots)'. If this argument is non-'NULL', it takes precedence over 'favoured' when the ballot box is being stuffed. |
rankMethod |
"safeRank" (default), "elected", or "rank". "rank" is a total ranking of the candidates, with ties broken at random. "elected" assigns rank=1 to elected candidates, rank=2 for eliminated candidates. |
countMethod |
countMethod "stv" (default) or "condorcet" |
countArgs |
List of args to be passed to countMethod (in addition to votes) |
exptName |
stem-name of experimental units e.g. "E". If 'NULL', then a 3-character string of capital letters is chosen at random. |
equiet |
'TRUE' to suppress all experimental output |
everbose |
'TRUE' to produce diagnostic output from the experiment |
A matrix of experimental results, of dimension by
,
where
is the number of elections and
is the number of
candidates. The first column is named "nBallots". Other columns indicate
the ranking of the eponymous candidate, and their margin over the
next-lower-ranked candidate.
data(food_election) testAdditions(food_election, arep = 2, favoured = "Strawberries", countArgs = list(safety = 0))
data(food_election) testAdditions(food_election, arep = 2, favoured = "Strawberries", countArgs = list(safety = 0))
Ballots are deleted at random from the ballot-box, with election results
computed once per 'dinc' ballot-deletions. The experiment terminates after a
specified number of ballots have been deleted, or a specified number of
ballot-counts have occurred. Note: these ballot-counts are correlated. Use
testFraction()
to experiment with independently-drawn samples from the
ballot-box.
testDeletions( votes, countMethod = "stv", countArgs = list(), dstart = NULL, dinc = NULL, dlimit = NULL, drep = NULL, rankMethod = "safeRank", exptName = NULL, equiet = FALSE, everbose = FALSE )
testDeletions( votes, countMethod = "stv", countArgs = list(), dstart = NULL, dinc = NULL, dlimit = NULL, drep = NULL, rankMethod = "safeRank", exptName = NULL, equiet = FALSE, everbose = FALSE )
votes |
A set of ballots, as in vote_2.3.2 |
countMethod |
"stv" (default) or "condorcet" |
countArgs |
List of args to be passed to 'countMethod' (in addition to 'votes') |
dstart |
Number of ballots in the first ballot-count (selected at random from 'votes', without replacement) |
dinc |
Number of ballots to be deleted in subsequent steps |
dlimit |
Maximum number of ballots to delete (in addition to 'dstart') |
drep |
Maximum number of elections (required if 'dinc=0') |
rankMethod |
"safeRank" (default), "elected", or "rank". "rank" is a total ranking of the candidates, with ties broken at random. "elected" assigns rank=1 to elected candidates, rank=2 for eliminated candidates. |
exptName |
stem-name of experimental units e.g. "E". If 'NULL', then a 3-character string of capital letters is chosen at random. |
equiet |
TRUE to suppress all experimental output |
everbose |
TRUE to produce diagnostic output from the experiment |
'SafeRankExpt' object, describing this experiment and its results
data(food_election) testDeletions(food_election) testDeletions(food_election, countMethod="stv", countArgs=list(complete.ranking=TRUE))
data(food_election) testDeletions(food_election) testDeletions(food_election, countMethod="stv", countArgs=list(complete.ranking=TRUE))
Starting from some number ('astart') of randomly-selected ballots, an
increasingly-large collection of randomly-selected ballots are counted. The
ballots are chosen independently without replacement for each experimental
unit; if you want to count decreasingly-sized portions of a single sample of
ballots, use testDeletions()
.
testFraction( votes = NULL, astart = NULL, ainc = NULL, arep = NULL, trep = NULL, rankMethod = "safeRank", countMethod = "stv", countArgs = list(), exptName = NULL, equiet = FALSE, everbose = FALSE )
testFraction( votes = NULL, astart = NULL, ainc = NULL, arep = NULL, trep = NULL, rankMethod = "safeRank", countMethod = "stv", countArgs = list(), exptName = NULL, equiet = FALSE, everbose = FALSE )
votes |
A numeric matrix: one row per ballot, one column per candidate |
astart |
Starting number of ballots (min 2) |
ainc |
Number of ballots to be added in each step. Must be non-negative. |
arep |
Number of repetitions of the test on each step. Required to be non-'NULL' if 'ainc=0' && is.null(trep)'. |
trep |
Limit on the total number of simulated elections. Required to be non-'NULL' if 'ainc=0 && is.null(arep)'. |
rankMethod |
"safeRank" (default), "elected", or "rank". "rank" is a total ranking of the candidates, with ties broken at random. "elected" assigns rank=1 to elected candidates, rank=2 for eliminated candidates. |
countMethod |
countMethod "stv" (default) or "condorcet" |
countArgs |
List of args to be passed to 'countMethod' (in addition to 'votes') |
exptName |
stem-name of experimental units e.g. "E". If 'NULL', then a 3-character string of capital letters is chosen at random. |
equiet |
'TRUE' to suppress all experimental output |
everbose |
'TRUE' to produce diagnostic output from the experiment |
SafeRankExpt object of experimental results.
data(food_election) testFraction(food_election, countMethod="condorcet", countArgs=list(safety=0.5,complete.ranking=TRUE)) testFraction(dublin_west, astart=20, ainc=10, arep=2, trep=3, countMethod="stv", rankMethod="elected", equiet=FALSE)
data(food_election) testFraction(food_election, countMethod="condorcet", countArgs=list(safety=0.5,complete.ranking=TRUE)) testFraction(dublin_west, astart=20, ainc=10, arep=2, trep=3, countMethod="stv", rankMethod="elected", equiet=FALSE)
Undocumented internal method from original code
translate.ties(ties, method)
translate.ties(ties, method)
ties |
undocumented |
method |
'f' for forward, 'b' for backward |
undocumented
These are the ballots cast by Labour MPs and MEPs in an election of their party's leader in 2010, as published by the Manchester Guardian. The names of the electors have been suppressed in this file, but are available at rangevoting.org, along with extensive commentary on the election.
data(uk_labour_2010)
data(uk_labour_2010)
A data frame with 266 observations and 5 candidates.
generic view() for classes defined in this package
view(object, ...)
view(object, ...)
object |
election object to be viewed |
... |
additional parameters, passed to formattable::formattable() |
html-formatted object, with side-effect in RStudio's Viewer pane
view method for approval object
## S3 method for class 'SafeVote.approval' view(object, ...)
## S3 method for class 'SafeVote.approval' view(object, ...)
object , ...
|
undocumented |
undocumented
view method for SafeVote.condorcet
## S3 method for class 'SafeVote.condorcet' view(object, ...)
## S3 method for class 'SafeVote.condorcet' view(object, ...)
object |
of type SafeVote.condorcet |
... |
view object
view method for plurality object
## S3 method for class 'SafeVote.plurality' view(object, ...)
## S3 method for class 'SafeVote.plurality' view(object, ...)
object , ...
|
undocumented |
undocumented
view method for score object
## S3 method for class 'SafeVote.score' view(object, ...)
## S3 method for class 'SafeVote.score' view(object, ...)
object , ...
|
undocumented |
undocumented
view method for the result of an stv() ballot-count
## S3 method for class 'SafeVote.stv' view(object, ...)
## S3 method for class 'SafeVote.stv' view(object, ...)
object |
object to be viewed |
... |
additional parameters, passed to formattable::formattable() |
html-formatted object
Find a winner and their margin of victory
winnerMargin(votes)
winnerMargin(votes)
votes |
cleaned ballots |
length-2 vector: the index of a winning candidate, and their margin of victory (0 if a tie, NA if no losers)
This data follows the structure of a 2016 Yale Faculty Senate election, with candidate names anonymised and permuted. Imported to SafeVote from STV v1.0.2, after applying the 'STV::cleanBallots' method to remove the ten empty rows.
data(yale_ballots)
data(yale_ballots)
A data frame with 479 observations and 44 candidates.