-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
137 update generic reports with irv winners #185
Changes from all commits
84c48c3
ec72c50
8bae62d
2e6f919
fe1eb34
e7e47e2
e253096
f792c9a
fe2e590
3d59c14
ebf983b
6529783
e339ff2
67e58ce
0c9dcd0
7102f98
d7dbc60
3012281
83410ad
3069a76
d6dd3f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,15 +6,19 @@ | |
import java.io.InputStreamReader; | ||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.math.BigDecimal; | ||
import java.nio.charset.Charset; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import java.util.List; | ||
import java.util.ArrayList; | ||
import java.util.Map; | ||
import java.util.HashMap; | ||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
import au.org.democracydevelopers.corla.endpoint.AbstractAllIrvEndpoint; | ||
import au.org.democracydevelopers.corla.model.ContestType; | ||
import au.org.democracydevelopers.corla.model.GenerateAssertionsSummary; | ||
import au.org.democracydevelopers.corla.model.IRVComparisonAudit; | ||
import au.org.democracydevelopers.corla.query.GenerateAssertionsSummaryQueries; | ||
import org.apache.log4j.LogManager; | ||
import org.apache.log4j.Logger; | ||
|
||
|
@@ -29,6 +33,9 @@ | |
|
||
import org.hibernate.query.Query; | ||
|
||
import us.freeandfair.corla.model.ComparisonAudit; | ||
import us.freeandfair.corla.model.Contest; | ||
import us.freeandfair.corla.model.ContestResult; | ||
import us.freeandfair.corla.persistence.Persistence; | ||
|
||
/** export queries **/ | ||
|
@@ -120,6 +127,10 @@ public static void customOut(final String query, final OutputStream os) { | |
**/ | ||
public static void jsonOut(final String query, final OutputStream os) { | ||
final Session s = Persistence.currentSession(); | ||
|
||
// Make sure the contest_result table has the right info for IRV. | ||
updateIRVContestResults(s); | ||
|
||
final String withoutSemi = query.replace(";", ""); | ||
final String jsonQuery = | ||
String.format("SELECT cast(row_to_json(r) as text)" + " FROM (%s) r", withoutSemi); | ||
|
@@ -153,6 +164,10 @@ public static void jsonOut(final String query, final OutputStream os) { | |
/** send query results to output stream as csv **/ | ||
public static void csvOut(final String query, final OutputStream os) { | ||
final Session s = Persistence.currentSession(); | ||
|
||
// Make sure the contest_result table has the right info for IRV. | ||
updateIRVContestResults(s); | ||
|
||
final String withoutSemi = query.replace(";", ""); | ||
s.doWork(new CSVWork(withoutSemi, os)); | ||
} | ||
|
@@ -168,7 +183,7 @@ public static List<String> getSqlFolderFiles() { | |
final String[] fileNames = {"batch_count_comparison.sql", "contest.sql", | ||
"contest_comparison.sql", "contest_selection.sql", "contests_by_county.sql", | ||
"tabulate.sql", "tabulate_county.sql", "upload_status.sql", "seed.sql", | ||
"ranked_ballot_interpretation.sql"}; | ||
"summarize_IRV.sql", "ranked_ballot_interpretation.sql"}; | ||
for (final String f : fileNames) { | ||
paths.add(String.format("%s/%s", folder, f)); | ||
} | ||
|
@@ -269,4 +284,63 @@ public static long custCopyOut(final String sql, OutputStream to, CopyManager cm | |
} | ||
} | ||
|
||
/** | ||
* This function deals, somewhat inelegantly, with the problem that the ContestResult data structure | ||
* used in most queries does not have correct values for things like winners, losers, margin, and | ||
* diluted margin for IRV contests. This function sets them manually from the | ||
* GenerateAssertionsSummary table, then flushes the database so that the csv reports, which are | ||
* based on database queries, get the right values from the contest_result table. | ||
* @param s The current Hibernate session. | ||
*/ | ||
private static void updateIRVContestResults(final Session s) { | ||
final String prefix = "[updateIRVContestResults]"; | ||
LOGGER.debug(String.format("%s %s.", prefix, | ||
"Updating IRV contest results from generate assertions summary")); | ||
|
||
final List<ComparisonAudit> comparisonAudits = ComparisonAuditQueries.sortedList(); | ||
|
||
for(final ComparisonAudit ca : comparisonAudits) { | ||
if(ca instanceof IRVComparisonAudit) { | ||
final Set<String> choices = new HashSet<>(); | ||
// Get the choices for the contest. These should be the same for all the contests, but | ||
// gather the whole set from all of them just in case. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to iterate over final Contest contest? It looks like line 309 is updating the choices set defined on line 304, yet choices has been defined final. (I think the rules are a bit weird/counter intuitive when objects are made final). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it's updating the object, but it's not reassigning the value, so 'final' is OK. |
||
for(final Contest contest : ca.contestResult().getContests()) { | ||
if (contest.description().equals(ContestType.IRV.toString())) { | ||
contest.choices().stream().map(ch -> choices.add(ch.name())); | ||
} else { | ||
// We have an IRVComparisonAudit for a not-IRV contest. Definitely not supposed to happen. | ||
final String msg = "IRV-type Comparison Audit encountered for non-IRV contest"; | ||
LOGGER.error(String.format("%s %s %s", prefix, msg, contest.name())); | ||
throw new RuntimeException(msg+" "+contest.name()); | ||
} | ||
} | ||
|
||
final ContestResult contestResult = ca.contestResult(); | ||
|
||
// Use the choices and the summary to update the contest result in the database. | ||
final Optional<GenerateAssertionsSummary> summary | ||
= GenerateAssertionsSummaryQueries.matching(ca.getContestName()); | ||
if(summary.isPresent()) { | ||
final String winner = summary.get().getWinner(); | ||
contestResult.setWinners(Set.of(winner)); | ||
choices.remove(winner); | ||
contestResult.setLosers(choices); | ||
contestResult.setMinMargin(((IRVComparisonAudit) ca).getMinMargin()); | ||
contestResult.setDilutedMargin(ca.getDilutedMargin()); | ||
} else { | ||
// If no summary is present, just set the winner to be blank, the losers to be everyone, | ||
// and the margins to be zero. | ||
LOGGER.debug(String.format("%s %s %s", prefix, "Couldn't find summary for IRV contest", | ||
ca.getContestName())); | ||
contestResult.setWinners(Set.of()); | ||
contestResult.setLosers(choices); | ||
contestResult.setMinMargin(0); | ||
contestResult.setDilutedMargin(BigDecimal.ZERO); | ||
} | ||
} | ||
} | ||
|
||
s.flush(); | ||
|
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the first sentence of the comment, clarify that the ContestResult structure does not have the correct values for those quantities for IRV.