lzear / votes

JS library for ranked voting systems
https://rank-votes.vercel.app
MIT License
23 stars 1 forks source link

Questions #64

Open narendersaini32 opened 2 years ago

narendersaini32 commented 2 years ago

Hi Izear First of all, I am very impressed with your work. I have a few questions.

  1. What's the meaning of weight in the below example?
  2. What's the use of scoresFromBallots?
  3. Can you share one example for Minimax Condorcet method?
  4. Is there any similar npm package for voting algorithms?

return scoresFromBallots( [ { ranking: [['Lion'], ['Bear'], ['Sheep']], weight: 4 }, { ranking: [['Sheep'], ['Bear'], ['Lion']], weight: 3 }, { ranking: [['Bear', 'Sheep'], ['Lion']], weight: 2 }, ], ['Lion', 'Bear', 'Sheep'], VotingSystem.Schulze, )

lzear commented 2 years ago

Hello @narendersaini32

Thank you very much for the message! I'm very happy to see someone reaching out about this project.

You motivated me to finish the release of a version 2. Unfortunately, I ended up unpublishing the whole package while trying to delete an invalid version 😕 Sorry if I cause any inconvenience. I will republish it in 24 hours.

  1. What's the meaning of weight in the below example?

    The weight property matches the strength of a vote. You're free to set any positive value, and you probably want it to match the number of voters that ranked candidates with the same order.

    // syntax for v2
    const borda = new Borda({
      candidates: ['Lion', 'Bear', 'Sheep'],
      ballots: [
        { ranking: [['Lion'], ['Bear'], ['Sheep']], weight: 2 }, // 2 voters voted "Lion > Bear > Sheep"
        { ranking: [['Sheep'], ['Bear'], ['Lion']], weight: 3 }, // 3 voters voted "Sheep > Bear > Lion"
      ],
    })

    You're free to keep the votes ungrouped, this also works:

    const borda = new Borda({
      candidates: ['Lion', 'Bear', 'Sheep'],
      ballots: [
        { ranking: [['Lion'], ['Bear'], ['Sheep']], weight: 1 },
        { ranking: [['Lion'], ['Bear'], ['Sheep']], weight: 1 },
        { ranking: [['Sheep'], ['Bear'], ['Lion']], weight: 1 },
        { ranking: [['Sheep'], ['Bear'], ['Lion']], weight: 1 },
        { ranking: [['Sheep'], ['Bear'], ['Lion']], weight: 1 },
      ],
    })

    There is an util to make the conversion, if you want to

    import { utils as votesUtils } from 'votes'
    utils.toWeightedBallots([
        [['a'], ['b'], ['c']],
        [['a'], ['b'], ['c']],
        [['b'], ['c'], ['a']],
      ]) // -> [ { ranking: [['a'], ['b'], ['c']], weight: 2 }, { ranking: [['b'], ['c'], ['a']], weight: 1 } ]
  2. What's the use of scoresFromBallots?

    I just realised that the readme code example was missing this line: `const { scoresToRanking, scoresFromBallots } = voteUtils

    scoresFromBallots (will soon be deprecated!) is a way to get a ScoreObject from an array of ballots and a voting system: an object with candidates as keys, and scores as value (the higher the better).

    Scores can be converted to rankings with the utility function scoresToRanking which orders candidates by score in descending order.

  3. Can you share one example for Minimax Condorcet method?

    With v2:

    import fill from 'lodash/fill'
    import { Minimax, utils as votesUtils } from 'votes'
    
    const balinski = votesUtils.toWeightedBallots([
     ...fill(new Array(33), [['a'], ['b'], ['c'], ['d'], ['e']]),
     ...fill(new Array(16), [['b'], ['d'], ['c'], ['e'], ['a']]),
     ...fill(new Array(3), [['c'], ['d'], ['b'], ['a'], ['e']]),
     ...fill(new Array(8), [['c'], ['e'], ['b'], ['d'], ['a']]),
     ...fill(new Array(18), [['d'], ['e'], ['c'], ['b'], ['a']]),
     ...fill(new Array(22), [['e'], ['c'], ['b'], ['d'], ['a']]),
    ])
    
    const election = new Minimax(
     votesUtils.matrixFromBallots(balinski, ['a', 'b', 'c', 'd', 'e']),
    )
    election.scores() // { a: -34, b: -2, c: -0, d: -58, e: -40 }
    election.ranking() // [ ['c'], ['b'], ['a'], ['e'], ['d'] ]
  4. Is there any similar npm package for voting algorithms?

    I searched a bit in the past without finding any. Today I found that one which looks good: https://github.com/Perlkonig/condorcet-ts

narendersaini32 commented 2 years ago

@lzear Thanks for your valuable time. Keep it up. 👍 One more question.

  1. In Wikipedia Minimax Condorcet method have three different variations. Which one you have implemented and is there a way for us to use all three variations using your package or any suggestion?

Screenshot 2022-04-16 at 7 21 27 AM

lzear commented 2 years ago

Very good point. The implementation was only using the margins variant. I just made an update so you can use the other variants:

new Minimax({
  candidates: ['a', 'b', 'c'],
  array: [[0, 1, 0], [0, 0, 0], [2, 1, 0]],
  // 'PAIRWISE_OPPOSITION' | 'WINNING_VOTES' | 'MARGINS' (default)
  variant: 'PAIRWISE_OPPOSITION',
}).scores()

I published a working example here: https://runkit.com/lzear/minimax-example


I managed to publish the package again: https://www.npmjs.com/package/votes But the v1 was lost, unfortunately

narendersaini32 commented 2 years ago

You are the best. 👍

narendersaini32 commented 2 years ago

Hi Izear Do we also have a code sandbox link for all algorithms demos? If not that's totally fine.

Screenshot 2022-04-18 at 8 16 55 AM

lzear commented 2 years ago

Hi again :)

It's not really a code sandbox, maybe playground would have been a better term. Anyway, it's here: rank-votes.vercel.app

I just added some links in the Readme:

This morning, I added Minimax to the voting systems in the demo (only the margins variant for now). Many other systems are still missing.

Thanks for showing interest in this project 🙏

maiconcarraro commented 2 years ago

@lzear first of all, amazing work!

I had the same question around the weight that is clear now, but I don't get it why it has an array with double entries here:

{ ranking: [['Bear', 'Sheep'], ['Lion']], weight: 2 },

Bear and Sheep same array, what is the difference for

{ ranking: [['Bear'], ['Sheep'], ['Lion']], weight: 2 },

Thank you in advance.

lzear commented 2 years ago

Hello @maiconcarraro

The library allows voters to indicate equal preferences in their ballots:

To get a better understanding of draws, you can maybe play around on https://rank-votes.vercel.app. Clicking the "✏️" icon, you can edit preferences by dragging candidates and generate preferences with draws. Or you can see another vote with draw here: https://www.elzear.de/poll/Uug62KMX

Here is an example of what happens with in a Borda votes: the points for the ranks get shared amongst the candidates.

Screenshot 2022-10-05 at 21 10 25

As a consumer of the library, you are of course free to disallow draws by making sure the rankings only contains arrays of length 1.

I hope the answer is understandable. Please ask if you need any additional clarifications, I'm very happy to see some people here 😄

maiconcarraro commented 2 years ago

Totally, makes a lot of sense. Thank you.