# Voting system characteristics

**URL:** <https://discuss.python.org/t/voting-system-characteristics/451>\
**Category:** Committers\
**Tags:** governance\
**Created:** [November 19, 2018, 12:44am UTC](https://discuss.python.org/t/voting-system-characteristics/451 "2018-11-19T00:44:46Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [November 19, 2018, 12:44am UTC](https://discuss.python.org/t/voting-system-characteristics/451/1 "2018-11-19T00:44:47Z")

</div>

Continuing the discussion from [Python Governance Electoral System](https://discuss.python.org/t/python-governance-electoral-system/290/113):

Splitting off a new topic here.

> [@Python Governance Electoral System](https://discuss.python.org/t/python-governance-electoral-system/290/113):
>
> At the end of [PEP 8001](https://www.python.org/dev/peps/pep-8001/), it says–
> 
> > The chances of [a voting cycle] occurring when there are 21 or more voters, though, is less than 1.5%. [1]
> 
> [1] [Voting Cycles](https://www.accuratedemocracy.com/l_cycles.htm)
> 
> To me, this reads like it’s a statement of actual probability. But when you go to the referenced source, it’s an historical statement about certain past real-world elections: “Less than 1.5% of real elections lead to a chance voting cycle when there are 21 voters or more.” …

This was a addressed in a sub-thread here, but not reflected in PEP 8001:

> [@Python Governance Electoral System](https://discuss.python.org/t/python-governance-electoral-system/290/101):
>
> But … I suspect 99.99% of the “real elections” referenced in that had no more than 3 viable candidates. We have a combination of a low number of voters with a high number of reasonable choices.
> 
> As a sanity check, I ran my own simulations using 100 voters each picking a full (no duplicate ranks) ranking of 7 candidates, picked uniformly at random from the 7! candidate permutations.
> 
> Slightly less than half(!) turned out to have a Condorcet winner. Worse, we won’t have 100 voters, and the fewer there are the worse the chances. Worse again, allowing rank duplicates also boosts the odds of not having a Condorcet winner.
> 
> Against that …
> 
> Anyway, bottom line: best guess is that we’ve grossly overestimated the odds of getting a Condorcet winner on the first try, due to our unusual combination of relatively few voters faced with an unusually high number of viable alternatives. Still think we _probably_ will, but it will no longer be a real surprise to me if we don’t.

But nothing new to say about that 😉

---

<div class="post-metadata">

**Author:** ![ambv](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ambv/32/25884_2.png) [@ambv](https://discuss.python.org/u/ambv)\
**Post date:** [November 27, 2018, 1:49pm UTC](https://discuss.python.org/t/voting-system-characteristics/451/2 "2018-11-27T13:49:23Z")

</div>

Could you run simulations with fewer candidate PEPs to see how much it makes things better?

PEP 8016 is very similar to PEP 8015 and both are very similar in spirit to my own PEP 8012. I would consider withdrawing 8012 if it increases the odds of avoiding a voting fiasco. I recall @steve.dower considered the same.

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [November 27, 2018, 7:21pm UTC](https://discuss.python.org/t/voting-system-characteristics/451/3 "2018-11-27T19:21:53Z")

</div>

> [@ambv](#):
>
> Could you run simulations with fewer candidate PEPs to see how much it makes things better?

Sure, but it’s not realistic. We shouldn’t let the voting system _drive_ anything. “Vote splitting” isn’t really a thing under Condorcet methods - at worst, two (or three …) similar PEPs get ranked equally by voters, which may increase the chance of a tie. Big deal. Then we vote again - and _that’s_ the point at which someone may wish to withdraw a PEP for “voting system reasons”.

Here are empirical probabilities of getting a flat-out Condorcet winner for various pairs of number of voters (in the first column) and number of candidates (in the first row). For example, if there are 12 voters and 2 candidates, the chance of a Condorcet winner is about 77%.

```
      1 2 3 4 5 6 7
  1 100 100 100 100 100 100 100 
  2 100 50 34 25 20 18 15 

 11 100 100 92 83 77 71 66 
 12 100 77 62 50 42 36 31 

 21 100 100 92 83 75 70 65 
 22 100 83 67 55 48 42 38 

 31 100 100 91 83 76 69 64 
 32 100 87 72 62 52 46 41 

 41 100 100 92 83 76 68 63 
 42 100 88 74 64 55 49 43 

 51 100 100 92 83 75 69 64 
 52 100 90 75 64 56 50 45 

 61 100 100 91 83 76 69 64 
 62 100 90 77 66 58 52 46 

 71 100 100 91 82 76 68 63 
 72 100 91 78 67 60 53 47 

 81 100 100 92 83 76 69 64 
 82 100 91 77 68 60 53 48 

 91 100 100 91 82 75 69 64 
 92 100 92 79 69 61 55 48 

101 100 100 91 82 75 68 64 
102 100 92 79 69 62 55 49 

```

Notes:

- Every voter picks a permutation of the candidates uniformly at random. This is highly unrealistic. In real life, many voters will have highly correlated rankings, _increasing_ the chance of getting a Condorcet winner.
- Every ballot here is a total ordering. We’re allowing partial orderings, which increase the chance of ties.
- Because these ballots are total orderings, a pairwise tie is impossible when there are an odd number of voters. That’s why the results for even numbers of voters are so much worse. The lack of a Condorcet winner in the latter cases isn’t so much due to preference cycles, but due to “the best” candidate getting at least as many votes in all one-on-one pairings, but also _tied_ in at least one.pairing. It’s not “a Condorcet winner” then.
- If you run this simulation multiple times, the last digits may vary. The results are approximate.

Finally, here’s the code that produced the output above:

```python
    def probcw(ncands, nvoters):
        from collections import defaultdict
        from itertools import combinations
        from random import shuffle

        ntries = ncw = 0
        oldmean = 0.0
        cands = list(range(ncands))
        V = defaultdict(int)
        while True:
            ntries += 1
            V.clear()
            for v in range(nvoters):
                shuffle(cands)
                for pair in combinations(cands, 2):
                    V[pair] += 1
            winner = None
            for i in cands:
                if all(i == j or V[i, j] > V[j, i] for j in cands):
                    winner = i
                    break
            if winner is not None:
                ncw += 1
            if ntries % 1000 == 0:
                mean = round(ncw / ntries, 3)
                if mean == oldmean:
                    return mean
                oldmean = mean

    print(" 1 2 3 4 5 6 7")
    for nvoters in range(1, 102, 10):
        for nvoters in range(nvoters, nvoters + 2):
            print(f"{nvoters:3d}", end=" ")
            for ncands in range(1, 8):
                pcw = round(probcw(ncands, nvoters) * 100)
                print(f"{pcw:3d}", end=" ")
            print()
        print()

```

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [November 29, 2018, 2:14am UTC](https://discuss.python.org/t/voting-system-characteristics/451/4 "2018-11-29T02:14:17Z")

</div>

> [@tim.one](#):
>
> Here are empirical probabilities of getting a flat-out Condorcet winner for various pairs of number of voters (in the first column) and number of candidates (in the first row)

FYI, some by-eyeball patterns in that table are legit:

- The stark difference between odd and even numbers of voters diminishes the more voters there are, and tends to 0. But it remains highly significant with a number of voters as high as the table goes up to.
- If the number of candidates \>= 3, the probability of getting a Condorcet winner pretty rapidly approaches a limit (as the number of voters increases) strictly less than 1.0, and lower the more candidates there are. For an odd number of voters, this is entirely due to preference cycles among the best-scoring candidates (for an even number of voters, it’s _also_ about pairwise ties).

As a sanity check, [here’s a theoretical derivation of probabilities](https://rangevoting.org/PuzzCondProb.html) as the number of voters goes to infinity. There is no closed form expression, but there is a relatively simple integral of functions related to the normal distribution. The “infinite number of voters” values in the table following are already approximately matched by the `voters=31` row of the earlier table:

| candidates | P(CW)\*100 |
| --- | --- |
| 1 | 100.0 |
| 2 | 100.0 |
| 3 | 91.2 |
| 4 | 82.5 |
| 5 | 74.9 |
| 6 | 68.5 |
| 7 | 63.1 |
| 8 | 58.5 |
| 9 | 54.5 |

> [@tim.one](#):
>
> Every voter picks a permutation of the candidates uniformly at random. This is highly unrealistic. In real life, many voters will have highly correlated rankings, _increasing_ the chance of getting a Condorcet winner.

Actually, that’s clear as mud 😉. It is unrealistic, but correlations can push things in _either_ direction, depending on their precise nature. In most studies I’ve stumbled into, the rate of Condorcet winners in real life elections were higher than the model above suggests - but in _some_ studies, the rate was lower. So “it depends” - but it’s unclear on _what_ it depends.
