Iterables

[1]:
from fractions import Fraction
import poisson_approval as pa

Iterable

The package provides a large variety of iterables to generate profiles, strategies or tau-vectors. In the following example, we iterate over all the tau-vectors whose coefficients are fractions of the given denominator 3, i.e. using a “grain” of \(\frac{1}{3}\):

[2]:
for tau in pa.IterableTauVectorGrid(denominator=3):
    print(tau)
<a: 1> ==> a
<a: 2/3, ab: 1/3> ==> a
<a: 2/3, ac: 1/3> ==> a
<a: 2/3, b: 1/3> ==> a
<a: 2/3, bc: 1/3> ==> a
<a: 2/3, c: 1/3> ==> a
<a: 1/3, ab: 2/3> ==> a
<a: 1/3, ab: 1/3, ac: 1/3> ==> a
<a: 1/3, ab: 1/3, b: 1/3> ==> a, b
<a: 1/3, ab: 1/3, bc: 1/3> ==> a, b
<a: 1/3, ab: 1/3, c: 1/3> ==> a
<a: 1/3, ac: 2/3> ==> a
<a: 1/3, ac: 1/3, b: 1/3> ==> a
<a: 1/3, ac: 1/3, bc: 1/3> ==> a, c
<a: 1/3, ac: 1/3, c: 1/3> ==> a, c
<a: 1/3, b: 2/3> ==> b
<a: 1/3, b: 1/3, bc: 1/3> ==> b
<a: 1/3, b: 1/3, c: 1/3> ==> a, b, c
<a: 1/3, bc: 2/3> ==> b, c
<a: 1/3, bc: 1/3, c: 1/3> ==> c
<a: 1/3, c: 2/3> ==> c
<ab: 1> ==> a, b
<ab: 2/3, ac: 1/3> ==> a
<ab: 2/3, b: 1/3> ==> b
<ab: 2/3, bc: 1/3> ==> b
<ab: 2/3, c: 1/3> ==> a, b
<ab: 1/3, ac: 2/3> ==> a
<ab: 1/3, ac: 1/3, b: 1/3> ==> a, b
<ab: 1/3, ac: 1/3, bc: 1/3> ==> a, b, c
<ab: 1/3, ac: 1/3, c: 1/3> ==> a, c
<ab: 1/3, b: 2/3> ==> b
<ab: 1/3, b: 1/3, bc: 1/3> ==> b
<ab: 1/3, b: 1/3, c: 1/3> ==> b
<ab: 1/3, bc: 2/3> ==> b
<ab: 1/3, bc: 1/3, c: 1/3> ==> b, c
<ab: 1/3, c: 2/3> ==> c
<ac: 1> ==> a, c
<ac: 2/3, b: 1/3> ==> a, c
<ac: 2/3, bc: 1/3> ==> c
<ac: 2/3, c: 1/3> ==> c
<ac: 1/3, b: 2/3> ==> b
<ac: 1/3, b: 1/3, bc: 1/3> ==> b, c
<ac: 1/3, b: 1/3, c: 1/3> ==> c
<ac: 1/3, bc: 2/3> ==> c
<ac: 1/3, bc: 1/3, c: 1/3> ==> c
<ac: 1/3, c: 2/3> ==> c
<b: 1> ==> b
<b: 2/3, bc: 1/3> ==> b
<b: 2/3, c: 1/3> ==> b
<b: 1/3, bc: 2/3> ==> b
<b: 1/3, bc: 1/3, c: 1/3> ==> b, c
<b: 1/3, c: 2/3> ==> c
<bc: 1> ==> b, c
<bc: 2/3, c: 1/3> ==> c
<bc: 1/3, c: 2/3> ==> c
<c: 1> ==> c

For most applications, it is not interesting to investigate all these tau-vectors because of the symmetries between candidates. To study them up to symmetries, use the option standardized=True:

[3]:
for tau in pa.IterableTauVectorGrid(denominator=3, standardized=True):
    print(tau)
<a: 1> ==> a
<a: 2/3, ab: 1/3> ==> a
<a: 2/3, b: 1/3> ==> a
<a: 2/3, bc: 1/3> ==> a
<a: 1/3, ab: 2/3> ==> a
<a: 1/3, ab: 1/3, ac: 1/3> ==> a
<a: 1/3, ab: 1/3, b: 1/3> ==> a, b
<a: 1/3, ab: 1/3, bc: 1/3> ==> a, b
<a: 1/3, ac: 1/3, b: 1/3> ==> a
<a: 1/3, b: 1/3, c: 1/3> ==> a, b, c
<a: 1/3, bc: 2/3> ==> b, c
<ab: 1> ==> a, b
<ab: 2/3, ac: 1/3> ==> a
<ab: 1/3, ac: 1/3, bc: 1/3> ==> a, b, c

Most iterables of the package provide options that enable to finely tune the outputs. In the following example, there are ballots \(a\) with a fixed share 1/7, ballots \(ab\) with a fixed share 2/7, and the remaining 4/7 of the voters are split between ballots \(b\), \(bc\) and \(c\), with a “relative” grain \(\frac{1}{4}\), i.e. an “absolute” grain \(\frac{4}{7} \cdot \frac{1}{4} = \frac{1}{7}\).

[4]:
iterable = pa.IterableTauVectorGrid(
    d_ballot_fixed_share={'a': Fraction(1, 7), 'ab': Fraction(2, 7)},
    ballots=['b', 'bc', 'c'],
    denominator=4
)
for tau in iterable:
    print(tau)
<a: 1/7, ab: 2/7, b: 4/7> ==> b
<a: 1/7, ab: 2/7, b: 3/7, bc: 1/7> ==> b
<a: 1/7, ab: 2/7, b: 3/7, c: 1/7> ==> b
<a: 1/7, ab: 2/7, b: 2/7, bc: 2/7> ==> b
<a: 1/7, ab: 2/7, b: 2/7, bc: 1/7, c: 1/7> ==> b
<a: 1/7, ab: 2/7, b: 2/7, c: 2/7> ==> b
<a: 1/7, ab: 2/7, b: 1/7, bc: 3/7> ==> b
<a: 1/7, ab: 2/7, b: 1/7, bc: 2/7, c: 1/7> ==> b
<a: 1/7, ab: 2/7, b: 1/7, bc: 1/7, c: 2/7> ==> b
<a: 1/7, ab: 2/7, b: 1/7, c: 3/7> ==> a, b, c
<a: 1/7, ab: 2/7, bc: 4/7> ==> b
<a: 1/7, ab: 2/7, bc: 3/7, c: 1/7> ==> b
<a: 1/7, ab: 2/7, bc: 2/7, c: 2/7> ==> b, c
<a: 1/7, ab: 2/7, bc: 1/7, c: 3/7> ==> c
<a: 1/7, ab: 2/7, c: 4/7> ==> c

For more information, cf. the Reference section on iterables.

Conditional Iterable

Say you have a test on tau-vectors, for example the fact of electing candidate \(a\) only:

[5]:
def test_a_wins(tau):
    return tau.winners == {'a'}

If you want to iterate over tau vectors that meet this test, you can use the classic Python syntax:

[6]:
for tau in pa.IterableTauVectorGrid(denominator=3):
    if test_a_wins(tau):
        print(tau)
<a: 1> ==> a
<a: 2/3, ab: 1/3> ==> a
<a: 2/3, ac: 1/3> ==> a
<a: 2/3, b: 1/3> ==> a
<a: 2/3, bc: 1/3> ==> a
<a: 2/3, c: 1/3> ==> a
<a: 1/3, ab: 2/3> ==> a
<a: 1/3, ab: 1/3, ac: 1/3> ==> a
<a: 1/3, ab: 1/3, c: 1/3> ==> a
<a: 1/3, ac: 2/3> ==> a
<a: 1/3, ac: 1/3, b: 1/3> ==> a
<ab: 2/3, ac: 1/3> ==> a
<ab: 1/3, ac: 2/3> ==> a

Alternatively, you can specify the test directly when defining the iterable:

[7]:
for tau in pa.IterableTauVectorGrid(denominator=3, test=test_a_wins):
    print(tau)
<a: 1> ==> a
<a: 2/3, ab: 1/3> ==> a
<a: 2/3, ac: 1/3> ==> a
<a: 2/3, b: 1/3> ==> a
<a: 2/3, bc: 1/3> ==> a
<a: 2/3, c: 1/3> ==> a
<a: 1/3, ab: 2/3> ==> a
<a: 1/3, ab: 1/3, ac: 1/3> ==> a
<a: 1/3, ab: 1/3, c: 1/3> ==> a
<a: 1/3, ac: 2/3> ==> a
<a: 1/3, ac: 1/3, b: 1/3> ==> a
<ab: 2/3, ac: 1/3> ==> a
<ab: 1/3, ac: 2/3> ==> a