Mirror of a Majority Judgment library for Java
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
6.2 KiB

1 year ago
1 year ago
1 year ago
1 year ago
  1. # Majority Judgment Library for Java
  2. [![MIT](https://img.shields.io/github/license/MieuxVoter/majority-judgment-library-java)](./LICENSE.md)
  3. [![Build Status](https://img.shields.io/github/workflow/status/MieuxVoter/majority-judgment-library-java/Java%20CI%20with%20Maven)](https://github.com/MieuxVoter/majority-judgment-library-java/actions)
  4. [![Release](https://img.shields.io/github/v/release/MieuxVoter/majority-judgment-library-java?sort=semver)](https://github.com/MieuxVoter/majority-judgment-library-java/releases)
  5. [![Join the Discord chat at https://discord.gg/rAAQG9S](https://img.shields.io/discord/705322981102190593.svg)](https://discord.gg/rAAQG9S)
  6. Test-driven java library to help deliberate using [Majority Judgment](https://mieuxvoter.fr/index.php/decouvrir/?lang=en).
  7. The goal is to be **scalable**, **reliable**, fast and extensible.
  8. We therefore use a _score-based algorithm_ and _no floating-point arithmetic_ whatsoever.
  9. ## Features
  10. - Supports billions of participants
  11. - Supports thousands of proposals
  12. - Handles default grades (static or normalized)
  13. - No floating-point arithmetic
  14. - Room for other deliberators (central, usual)
  15. ## Example Usage
  16. Collect the **tallies** for each Proposal (aka. Candidate) by your own means,
  17. provide them to the `MajorityJudgmentDeliberator`, and get back the **rank** of each Proposal.
  18. Let's say you have the following tally:
  19. | | To Reject | Poor | Passable | Somewhat Good | Good | Very Good | Excellent |
  20. |------------|-----------|------|----------|---------------|------|-----------|-----------|
  21. | Proposal A | 4 | 5 | 2 | 1 | 3 | 1 | 2 |
  22. | Proposal B | 3 | 6 | 2 | 2 | 2 | 1 | 2 |
  23. | … | | | | | | | |
  24. | | | | | | | | |
  25. > A _Tally_ is the amount of judgments received per grade, by each proposal.
  26. ``` java
  27. DeliberatorInterface mj = new MajorityJudgmentDeliberator();
  28. TallyInterface tally = new Tally(new ProposalTallyInterface[] {
  29. // Amounts of judgments received for each grade, from "worst" grade to "best" grade
  30. new ProposalTally(new Integer[]{4, 5, 2, 1, 3, 1, 2}), // Proposal A
  31. new ProposalTally(new Integer[]{3, 6, 2, 1, 3, 1, 2}), // Proposal B
  32. // …
  33. }, 18);
  34. ResultInterface result = mj.deliberate(tally);
  35. // Each proposal result has a rank, and results are returned by input order
  36. assert(2 == result.getProposalResults().length);
  37. assert(2 == result.getProposalResults()[0].getRank()); // Proposal A
  38. assert(1 == result.getProposalResults()[1].getRank()); // Proposal B
  39. ```
  40. Got more than 2³² judges? Use a `Long[]` in a `ProposalTally`.
  41. Got even more than that ? Use `BigInteger`s !
  42. ### Using a static default grade
  43. Want to set a static default grade ? Use a `StaticDefaultTally` instead of a `Tally`.
  44. ```java
  45. Integer amountOfJudges = 18;
  46. Integer defaultGrade = 0; // "worst" grade (usually "to reject")
  47. TallyInterface tally = new StaticDefaultTally(new ProposalTallyInterface[] {
  48. // Amounts of judgments received of each grade, from "worst" grade to "best" grade
  49. new ProposalTally(new Integer[]{4, 5, 2, 1, 3, 1, 2}), // Proposal A
  50. new ProposalTally(new Integer[]{3, 6, 2, 1, 3, 1, 2}), // Proposal B
  51. // …
  52. }, amountOfJudges, defaultGrade);
  53. ```
  54. ### Using normalized tallies
  55. In some polls with a very high amount of proposals, where participants cannot be expected to judge every last one of them, it may make sense to normalize the tallies instead of using a default grade.
  56. To that effect, use a `NormalizedTally` instead of a `Tally`.
  57. ```java
  58. TallyInterface tally = new NormalizedTally(new ProposalTallyInterface[] {
  59. // Amounts of judgments received of each grade, from "worst" grade to "best" grade
  60. new ProposalTally(new Integer[]{4, 5, 2, 1, 3, 1, 2}), // Proposal A
  61. new ProposalTally(new Integer[]{3, 6, 2, 1, 3, 1, 2}), // Proposal B
  62. // …
  63. });
  64. ```
  65. > This normalization uses the Least Common Multiple, in order to skip floating-point arithmetic.
  66. ### Collect a Tally from judgments
  67. It's usually best to use structured queries (eg: in SQL) directly in your database to collect the tallies, since it scales better with high amounts of participants, but if you must you can collect the tally directly from individual judgments, with a `CollectedTally`.
  68. ```java
  69. Integer amountOfProposals = 2;
  70. Integer amountOfGrades = 4;
  71. DeliberatorInterface mj = new MajorityJudgmentDeliberator();
  72. CollectedTally tally = new CollectedTally(amountOfProposals, amountOfGrades);
  73. Integer firstProposal = 0;
  74. Integer secondProposal = 1;
  75. Integer gradeReject = 0;
  76. Integer gradePassable = 1;
  77. Integer gradeGood = 2;
  78. Integer gradeExcellent = 3;
  79. // Collect the judgments, one-by-one, with `collect()`
  80. tally.collect(firstProposal, gradeReject);
  81. tally.collect(firstProposal, gradeReject);
  82. tally.collect(firstProposal, gradePassable);
  83. tally.collect(firstProposal, gradePassable);
  84. tally.collect(firstProposal, gradePassable);
  85. tally.collect(firstProposal, gradeExcellent);
  86. tally.collect(firstProposal, gradeExcellent);
  87. tally.collect(secondProposal, gradeReject);
  88. tally.collect(secondProposal, gradeReject);
  89. tally.collect(secondProposal, gradeGood);
  90. tally.collect(secondProposal, gradeGood);
  91. tally.collect(secondProposal, gradeGood);
  92. tally.collect(secondProposal, gradeExcellent);
  93. tally.collect(secondProposal, gradeExcellent);
  94. // …
  95. ResultInterface result = mj.deliberate(tally);
  96. ```
  97. ## Gondor calls for Help!
  98. We are not accustomed to Java library development and we'd love reviews from seasoned veterans !
  99. Feel free to fork and request merges for your contributions and active readings !
  100. ## Run the test-suite
  101. Install [maven](https://maven.apache.org), and run:
  102. mvn test
  103. > Maven is available as a debian package: `apt install maven`
  104. You can also use a runner in Eclipse. (`CTRL+F11` to rerun)
  105. ## License
  106. [MIT](./LICENSE.md) → _Do whatever you want except complain._
  107. Majority Judgment itself is part of the Commons, obviously.
  108. ## Fund us
  109. We'd love to invest more energy in Majority Judgment development.
  110. Please consider funding us, every bit helps : https://www.paypal.com/donate/?hosted_button_id=QD6U4D323WV4S