Objects mutability
If the Condorcet API is highly flexible and accepts many input formats, its object-oriented mode enables the most advanced and elegant use cases. Users can interact with certain objects in user space that are shared with the Condorcet engine, resulting in immediate and fully supported outcomes. The philosophy behind Condorcet PHP is that nearly everything is mutable—only the Result
object exhibits some degree of partial immutability. While this approach may be debated, given the need for strong integrity in voting procedures, it also allows for powerful manipulation and simulation capabilities. Achieving immutability in your implementation is simply a matter of avoiding mutation methods and/or not retaining references to objects passed to Condorcet (or allowing Condorcet to create them itself). The responsibility for this lies with the implementer. To provide a safety net, the API maintains a history of changes for Votes and Candidates objects, ensuring that no modification is forgotten. This is similar to the cryptographic checksum (see the dedicated section).
Overview
It should be noted that internally Condorcet only works with objects. When another input method is used, it creates the objects itself, for the Candidate
objects it tries to match them to pre-existing objects. Here is an example. <<< @/code_snippets/mutability_overview.php
Keeping the previous example, look what happens if I change a candidate name. <<< @/code_snippets/candidate_name_changes.php
Or the Ranking: The results of my election are modified instantly (only new results objects). <<< @/code_snippets/vote_ranking_changes.php
Multiples elections per object
use \CondorcetPHP\Condorcet\{Candidate, Election, Vote};
// Create objetcs
$candidateA = new Candidate('A');
$candidateB = new Candidate('B');
$candidateC = new Candidate('C');
$election1 = new Election;
$election1->allowsVoteWeight(true);
$election1->addCandidate($candidateA);
$election1->addCandidate($candidateB);
$election1->addCandidate($candidateC);
$election2 = clone $election1;
$voteUnique1 = new Vote([1 => $candidateA, 2=> $candidateB, 3 => $candidateC]);
$voteUnique2 = clone $voteUnique1;
$voteMix = clone $voteUnique1;
$voteMix->setWeight(2);
$voteUnique1->setWeight(3);
$voteUnique2->getWeight(); // 1
// register candidates + $voteMix in both elections
foreach([$election1, $election2] as $e) {
$e->addVote($voteMix); // In both election
}
// Add other vote to their elections
$election1->addVote($voteUnique1);
$election2->addVote($voteUnique2);
// Count Links for Votes
$voteUnique1->countLinks(); // 1
$voteUnique1->getLinks()[0] === $election1; // True
$voteUnique2->countLinks(); // 1
$voteUnique2->getLinks()[0] === $election2; // True
$voteMix->countLinks(); // 2
$voteMix->getLinks()[0] === $election1; // True
$voteMix->getLinks()[1] === $election2; // True
// Count Links for Candidates
$candidateA->countLinks(); // 2
$candidateA->getLinks()[0] === $election1; // True
$candidateA->getLinks()[1] === $election2; // True
$election1->getWinner() === $election2->getWinner(); // True
$voteMix->setRanking([1 => $candidateB, 2=> $candidateC, 3 => $candidateA]);
$election1->getWinner() === $election2->getWinner(); // False
$election1->getWinner() === $candidateA; // True
$election2->getWinner() === $candidateB; // True
Limitations
In the case of using an external data handler, used to manage up to billions of votes in an election, the correspondence between your objects and those used internally by Condorcet is no longer guaranteed, as these are destroyed during storage and then recreated. However, your objects in user space are properly unlinked from the election.