mieuxvoter / majority-judgment
Rank the candidates of your polls using Majority Judgment with a fast, robust, interface-oriented and scalable algorithm.
Package info
github.com/MieuxVoter/majority-judgment-library-php
pkg:composer/mieuxvoter/majority-judgment
Requires
- php: >=8.2|^9
Requires (Dev)
- phpunit/phpunit: ~12
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-30 01:16:55 UTC
README
Rank candidates of Majority Judgment polls.
Features
- Majority judgment deliberation from merit profiles
- Fast & extensible
- Supports billions of voters
- Supports thousands of candidates
- Test-Driven Development
- No floating-point arithmetic
- Using composer and namespaces
- Also available as a single file
Installation
Require it in your own project, using composer:
composer require mieuxvoter/majority-judgment
If you do not have composer, for example when writing a Wordpress plugin, you can also download the whole, bundled library from a single file.
Usage example
Let's say you have a poll with three candidates and merit profiles like so:
You can get the rank of each candidate like so:
use MieuxVoter\MajorityJudgment\MajorityJudgment; use MieuxVoter\MajorityJudgment\Model\Tally\ArrayPollTally; $grades = [ "to reject", "insufficient", "passable", "somewhat good", "good", "very good", "excellent", ]; $proposals = [ "Arancini", "Burger", "Chips", ]; $meritProfiles = [ [1, 1, 4, 3, 7, 4, 1], // for each proposal, tally the [2, 2, 5, 5, 5, 0, 2], // amount of judgments for each grade [0, 1, 2, 1, 6, 7, 4], // from "worst" grade to "best" grade ]; $pollTally = new ArrayPollTally($meritProfiles); $mj = new MajorityJudgment(); $result = $mj->deliberate($pollTally); foreach($result->getProposalResultsRanked() as $proposalResult) { // … Do something, for example: print(sprintf( "#%d %s (%s)\n", $proposalResult->getRank(), $proposals[$proposalResult->getIndex()], $grades[$proposalResult->getMedian()], )); } // #1 Chips (very good) // #2 Arancini (good) // #3 Burger (somewhat good)
Tip
These images were generated with our online merit profile tool.
Unbalanced Tallies
If your tally is unbalanced, because some proposals received more judgments than others, you will need to balance the tally using one of the provided balancing methods (or your own).
Using ad hoc normalization
This is akin to using percentages to resolve Majority Judgment, instead of tallies.
This kind of balancing is relevant when:
- there are many proposals in your poll
- users cannot be expected to judge them all
- you ensured that participation is somewhat balanced
- you excluded proposals that received too little participation
$meritProfiles = [ [3, 3, 3, 3, 3], [0, 1, 2, 3, 4], [0, 2, 4, 6, 8], [7, 7, 7, 7, 7], ]; $balanceUsingNormalization = true; $pollTally = new ArrayPollTally($meritProfiles); $mj = new MajorityJudgment(); $result = $mj->deliberate($pollTally, $balanceUsingNormalization); // Ranks: // 3 // 1 // 1 // 3
Warning
Due to a design choice (not using a library for big integers), this ad hoc normalization is limited to a little over 3 billion voters. If you have more voters than that, its result is unpredictable — it might work, or it might glitch out by buffer overflow.
Using a Static Default Grade
The most common balancing strategy is to consider missing judgments as of the "worst" grade. This incentivizes candidates to be clear and to promote themselves.
Here's how one can use the Balancer to balance a poll tally:
use MieuxVoter\MajorityJudgment\Balancer; $initialPollTally = new ArrayPollTally( [ "Arancini" => [1, 2, 3, 4], "Burger" => [4, 0, 0, 0], "Chips" => [0, 1, 1, 2], ], ); $balancedPollTally = Balancer::balanceUsingStaticDefaultGrade($initialPollTally); print_r($balancedPollTally->getProposalsTallies()[0]->getGradesTallies()); print_r($balancedPollTally->getProposalsTallies()[1]->getGradesTallies()); print_r($balancedPollTally->getProposalsTallies()[2]->getGradesTallies()); // [ 1, 2, 3, 4 ] // [ 10, 0, 0, 0 ] // [ 6, 1, 1, 2 ]
Using the Median Grade
I can't fathom why you'd want this, but here it is anyway:
$initialPollTally = new ArrayPollTally( [ "Arancini" => [1, 2, 3, 4], "Burger" => [2, 0, 0, 0], "Chips" => [0, 1, 1, 0], ], ); $balancedPollTally = Balancer::balanceUsingMedianDefaultGrade($initialPollTally); print_r($balancedPollTally->getProposalsTallies()[0]->getGradesTallies()); print_r($balancedPollTally->getProposalsTallies()[1]->getGradesTallies()); print_r($balancedPollTally->getProposalsTallies()[2]->getGradesTallies()); // [1, 2, 3, 4] // [10, 0, 0, 0] // [0, 9, 1, 0]
Warning
This balancing strategy is not very interesting, nor fair. You probably should prefer normalization, or using the lowest grade.
Testing
See the tests in test/.
composer install
vendor/bin/phpunit test