# 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


## 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