diff --git a/README.md b/README.md index 681237e..0f0c9d1 100644 --- a/README.md +++ b/README.md @@ -140,17 +140,17 @@ ResultInterface result = mj.deliberate(tally); - [x] Ranking - [x] Release v0.1.0 - [x] Guess the amount of judges -- [ ] Allow defining a default grade +- [x] Allow defining a default grade - [x] Static Grade (configurable) - - [x] Normalization (using least common multiple) - - [ ] Median Grade + - [x] Normalization (using Least Common Multiple) + - [x] Median Grade - [ ] Release v0.2.0 - [ ] Publish on package repositories - [ ] Gradle - [ ] Maven - [ ] … ? (please share your knowledge to help us!) - [ ] Release v0.3.0 -- [ ] Use it somewhere in another app, adjust API as needed (one last time) +- [ ] Use it somewhere in an application, adjust API as needed (one last time) - [ ] Release v1.0.0 diff --git a/src/main/java/fr/mieuxvoter/mj/MedianDefaultTally.java b/src/main/java/fr/mieuxvoter/mj/MedianDefaultTally.java new file mode 100644 index 0000000..4a665f1 --- /dev/null +++ b/src/main/java/fr/mieuxvoter/mj/MedianDefaultTally.java @@ -0,0 +1,43 @@ +package fr.mieuxvoter.mj; + +import java.math.BigInteger; + +/** + * Fill the missing judgments into the median grade. + * Useful when the proposals have not received the exact same amount of votes and + * the median grade is considered a sane default. + */ +public class MedianDefaultTally extends Tally implements TallyInterface { + + public MedianDefaultTally(ProposalTallyInterface[] proposalsTallies, BigInteger amountOfJudges) { + super(proposalsTallies, amountOfJudges); + fillWithDefaultGrade(); + } + + public MedianDefaultTally(ProposalTallyInterface[] proposalsTallies, Long amountOfJudges) { + super(proposalsTallies, amountOfJudges); + fillWithDefaultGrade(); + } + + public MedianDefaultTally(ProposalTallyInterface[] proposalsTallies, Integer amountOfJudges) { + super(proposalsTallies, amountOfJudges); + fillWithDefaultGrade(); + } + + protected void fillWithDefaultGrade() { + int amountOfProposals = getAmountOfProposals(); + for (int i = 0 ; i < amountOfProposals ; i++) { + ProposalTallyInterface proposal = getProposalsTallies()[i]; + ProposalTallyAnalysis analysis = new ProposalTallyAnalysis(proposal); + Integer defaultGrade = analysis.getMedianGrade(); + BigInteger amountOfJudgments = proposal.getAmountOfJudgments(); + BigInteger missingAmount = this.amountOfJudges.subtract(amountOfJudgments); + int missingSign = missingAmount.compareTo(BigInteger.ZERO); + assert(0 <= missingSign); // ERROR: More judgments than judges! + if (0 < missingSign) { + proposal.getTally()[defaultGrade] = proposal.getTally()[defaultGrade].add(missingAmount); + } + } + } + +} diff --git a/src/test/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberatorTest.java b/src/test/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberatorTest.java index 68fadb8..3e1f81c 100644 --- a/src/test/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberatorTest.java +++ b/src/test/java/fr/mieuxvoter/mj/MajorityJudgmentDeliberatorTest.java @@ -213,7 +213,7 @@ class MajorityJudgmentDeliberatorTest { } @Test - @DisplayName("Test static default grade with thousands of proposals") + @DisplayName("Test static default grade with thousands of proposals and millions of judges") public void testStaticDefaultWithThousandsOfProposals() { int amountOfProposals = 1337; Integer amountOfJudges = 60000000; @@ -257,6 +257,30 @@ class MajorityJudgmentDeliberatorTest { // } // } + @Test + @DisplayName("Test with a median default grade") + public void testMedianDefaultGrade() { + Integer amountOfJudges = 42; + DeliberatorInterface mj = new MajorityJudgmentDeliberator(); + TallyInterface tally = new MedianDefaultTally(new ProposalTallyInterface[] { + new ProposalTally(new Integer[]{ 0, 0, 1 }), + new ProposalTally(new Integer[]{ 0, 1, 0 }), + new ProposalTally(new Integer[]{ 1, 1, 1 }), + new ProposalTally(new Integer[]{ 1, 0, 1 }), + new ProposalTally(new Integer[]{ 1, 0, 0 }), + }, amountOfJudges); + + ResultInterface result = mj.deliberate(tally); + + assertNotNull(result); + assertEquals(5, result.getProposalResults().length); + assertEquals(1, result.getProposalResults()[0].getRank()); + assertEquals(2, result.getProposalResults()[1].getRank()); + assertEquals(3, result.getProposalResults()[2].getRank()); + assertEquals(4, result.getProposalResults()[3].getRank()); + assertEquals(5, result.getProposalResults()[4].getRank()); + } + @Test @DisplayName("Test normalized tallies with thousands of (prime) proposals") public void testNormalizedWithThousandsOfPrimeProposals() {