Skip to content

Commit

Permalink
Improvements based on @michelleblom's review.
Browse files Browse the repository at this point in the history
  • Loading branch information
vteague committed Nov 20, 2024
1 parent 1c76f4c commit 37b8d5d
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ protected void reset() {
* to the IRV ones. Although the countContest function isn't really useful or meaningful for IRV,
* it is called here because it actually does a lot of other useful things, such as setting the
* number of allowed winners and gathering all the results across counties.
* Assumption: Contest names are unique.
* @return A list of all ContestResults for IRV contests.
* @throws RuntimeException if it encounters contests with a mix of IRV and any other contest type.
* Assumption: Contest names are unique.
*/
protected static List<ContestResult> getIRVContestResults() {
final String prefix = "[getIRVContestResults]";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ public String endpointBody(final Request the_request, final Response the_respons

/**
* Compute sample sizes for all contests for which CountyContestResults exist in the database.
* This method ignores manifests, instead using the count of uploaded CSVs. This means that the
* estimate may differ from the estimate computed by estimatedSampleSize() during the audit, if
* the manifest has more votes than the CVR file.
* @return A list of string arrays containing rows with the following data: county name,
* contest name, contest type, single or multi-jurisdictional, ballots cast, diluted margin,
* and estimated sample size.
Expand All @@ -143,6 +146,7 @@ public String estimateSampleSizes() {
// in a ContestResult for an IRV contest will not be used. In the call to ContestCounter
// (countAllContests), all persisted CountyContestResults will be accessed from the database,
// grouped by contest, and accumulated into a single ContestResult.
// Set the useManifests flag to false, to tell contest counter to use CVR count instead.
final List<ContestResult> countedCRs = ContestCounter.countAllContests(false).stream().peek(cr ->
cr.setAuditReason(AuditReason.OPPORTUNISTIC_BENEFITS)).toList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ private ContestCounter() {
/**
* Group all CountyContestResults by contest name and tally the votes
* across all counties that have reported results.
* This only works for plurality - not valid, and not needed, for IRV.
*
* @return List<ContestResult> A high level view of contests and their
* participants.
* If 'useManifests' is true, it calculates the total universe size from the uploaded manifests -
* this is important for the validity of the audit step. useManifests can be false for sample-size
* estimation, where we expect that counties may not have uploaded valid manifests - in this case,
* universe size is calculated by counting the CVRs.
* The actual tallying is valid only for plurality - it is not valid, and not needed, for IRV.
* However, this function may still be useful for IRV, e.g. for gathering contests together by
* name and calculating their universes.
* @return List<ContestResult> A high level view of contests and their participants.
*/
public static List<ContestResult> countAllContests(boolean useManifests) {
return
Expand Down Expand Up @@ -82,8 +86,8 @@ public static Set<Integer> pairwiseMargins(final Set<String> winners,
* @param countyContestResults the county-by-county contest results, which are useful for plurality.
* @param useManifests whether to use manifests to compute the total number of ballots. This
* *must* be true when counting for audits - it can be false only when
* doing sample size estimation. In this case, it computes the total number
* of ballots based on the (untrusted) CVRs.
* doing pre-audit sample size estimation. In this case, it computes
* the total number of ballots based on the (untrusted) CVRs.
**/
public static ContestResult countContest(final Map.Entry<String, List<CountyContestResult>> countyContestResults,
boolean useManifests) {
Expand Down Expand Up @@ -125,12 +129,13 @@ public static ContestResult countContest(final Map.Entry<String, List<CountyCont
.map(cr -> cr.county())
.collect(Collectors.toSet()));

Long ballotCount;
if(useManifests) {
ballotCount = BallotManifestInfoQueries.totalBallots(contestResult.countyIDs());
} else {
ballotCount = countCVRs(contestResult);
}
// If we are supposed to use manifests, set the ballotCount to their indicated total, otherwise
// count the CVRs.
final Long ballotCount = useManifests ?
BallotManifestInfoQueries.totalBallots(contestResult.countyIDs()) : countCVRs(contestResult);
LOGGER.debug(String.format("%s Contest %s counted %s manifests.", "[countContest]", contestName,
useManifests ? "with" : "without"));

final Set<Integer> margins = pairwiseMargins(contestResult.getWinners(),
contestResult.getLosers(),
voteTotals);
Expand All @@ -154,12 +159,14 @@ public static ContestResult countContest(final Map.Entry<String, List<CountyCont
}

/**
* Calculate the size of the audit universe by counting CVRs. This is the total number
* of CVRs in all counties that have any votes in the contest. Used for sample-size estimation.
* Calculate the size of the audit universe for a given contest by counting CVRs. This is the
* total, over all counties that have any votes in the contest, of the total number of CVRs in the
* county. Used for preliminary sample-size estimation before the audit.
* For example, if a county had 10,000 CVRs, of which only 500 contained the contest, it would
* contribute 10,000 to the total.
* Note this should *not* be used for auditing, only for sample-size estimation - the audit
* calculation should get this value from the manifests, not the CVRs.
* Note this should *not* be used during auditing, only for preliminary sample-size estimation in
* advance of the audit. During auditing, the sample-size estimate calculation should get this
* value from the manifests, not the CVRs.
* @param contestResult the contestResult for this contest.
* @return the sum, over all counties that contain the contest, of the total number of CVRs in
* that county. This will be 0 if either the contestResult has no counties, or the counties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ public List<ContestResult> countAndSaveContests(final Set<ContestToAudit> cta) {
LOGGER.debug(String.format("[countAndSaveContests: cta=%s]", cta));
final Map<String, AuditReason> tcr = targetedContestReasons(cta);

// Count the contests, using the trusted Manifests to get the universe sizes.
return ContestCounter.countAllContests(true).stream().map(cr -> {
cr.setAuditReason(tcr.getOrDefault(cr.getContestName(),
AuditReason.OPPORTUNISTIC_BENEFITS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public static void afterAll() {
public void IRVContestMakesIRVAudit() {
testUtils.log(LOGGER, "IRVContestMakesIRVAudit");

// Set up the contest results from the stored data.
// Set up the contest results from the stored data. Use manifests for this test (though it
// shouldn't matter because for this sample data, the manifests and CVRs have the same totals).
List<ContestResult> results = ContestCounter.countAllContests(true);

// Find all the ContestResults for TinyIRV - there should be one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ public void setup() {
* @param testFileName the name of the test file - must be different for each test.
*/
protected static void runMain(final String testFileName) {
final String propertiesFile = tempConfigPath +testFileName+"-test.properties";
final String propertiesFile = tempConfigPath + testFileName + "-test.properties";
try {
FileOutputStream os = new FileOutputStream(propertiesFile);
final StringWriter sw = new StringWriter();
config.store(sw, "Ephemeral database config for Demo1");
config.store(sw, "Ephemeral database config for "+testFileName);
os.write(sw.toString().getBytes());
os.close();
} catch (Exception e) {
LOGGER.error("Couldn't write Demo1-test.properties. "+e.getMessage(), e);
LOGGER.error("Couldn't write " + testFileName + "-test.properties. "+e.getMessage(), e);
}
main(propertiesFile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
#Placeholder database config for Demo1
#Ephemeral database config for Demo1
#Fri Nov 15 15:26:53 AEDT 2024
raire_url=http\://localhost\:8080
generate_assertions_mock_port=8110
hibernate.driver=org.postgresql.Driver
hibernate.pass=corlasecret
hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
get_assertions_mock_port=8111
hibernate.show_sql=false
hibernate.user=corlaadmin
hibernate.url=jdbc\:postgresql\://localhost\:32774/corla?loggerLevel\=OFF

0 comments on commit 37b8d5d

Please sign in to comment.