julien-boudry / Condorcet

Command line application and PHP library, providing an election engine with a high-level interface. Native support 20+ voting methods, easy to extend. Support simple elections with ease or billions of votes in low resource environment. Intensively tested and highly polyvalent.
https://www.condorcet.io
MIT License
119 stars 11 forks source link

[Public API Reform] Do a really independant Pairwise object #146

Closed julien-boudry closed 1 year ago

julien-boudry commented 1 year ago

Context

Actually, the Pairwise object is strongly coupled with its election Object. Make it hard to create custom pairwise calculations, simulations, filters... Force to mock it via a fake heavy Election object.

Proposal

Decouple Pairwise from Election. Make it accept various interfaces as vote collection/iterators instead of an Election object.

Breaking changes

Could be safe publicly, pairwise is not really exposed. Could be safe for the internal method API, or minor?

julien-boudry commented 1 year ago

@LiamM32

LiamM32 commented 1 year ago

Sure. This is to allow only a specified portion of all votes to be processed for pairwise results, right?

Earlier I was thinking that some of the Election functions related to processing information from votes can be moved into a trait in a new file, and be included in both the Election class and a new class.

But you would know better than me how it's best to achieve the desired functionality. It would be nice to have a good way to determine pairwise results for a specified set of voters identified by a tag. Even for the conventional Schulze method or Ranked Pairs, it might be desired to get some statistics for certain demographics of voters, even if this isn't used to determine the end result.

LiamM32 commented 1 year ago

The Schulze STV method that I am working on has a function to determine how many votes prefer a candidate to all other candidates in a set. Perhaps this belongs in pairwise. Though I didn't put it there because I don't really understand how the pairwise object works.

julien-boudry commented 1 year ago

No, it's about iterating over votes.

        foreach ($this->getElection()->getVotesValidUnderConstraintGenerator() as $oneVote) {
            $weight = $oneVote->getWeight($election);
            $oneRanking = $oneVote->getContextualRankingWithoutSort($election);

           if (  count($oneRanking) >= 1 &&
                 count($oneRanking[1]) === 1 &&
                $yourExpectedWinnerKey === $this->getElection()->getCandidateKey($oneRanking[1])
           ) {
              // $yourExpectedWinner is the first
           }
        }
LiamM32 commented 1 year ago

To be honest, I don't really understand why Pairwise needs to be it's own object class. It's massively complicated for what it does. Why not just have a function in the vote object itself to determine which of two candidates is preferred, & methods can iterate over all votes in a foreach loop? If you just want cache for pairwise results, isn't there a simpler implementation that isn't any slower than the current one?