pull/4/head
crflynn 2018-01-08 22:12:31 -05:00
rodzic 2962ca5549
commit 0d7b1c3bd1
11 zmienionych plików z 234 dodań i 7 usunięć

Wyświetl plik

@ -15,3 +15,5 @@ sphinx-rtd-theme = "*"
[dev-packages]
ptpython = "*"
pytest = "*"
pytest-cov = "*"

87
Pipfile.lock wygenerowano
Wyświetl plik

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "9ac7ae345861a62cb069f25af526478a0d6ad267299653f8ff51a35e4afc0abb"
"sha256": "c77bc9703a73f19a9d5b39563ef31fe3a6af909adc98ee2c316ae46f02d34f5e"
},
"host-environment-markers": {
"implementation_name": "cpython",
@ -179,10 +179,10 @@
},
"sphinx": {
"hashes": [
"sha256:fdf77f4f30d84a314c797d67fe7d1b46665e6c48a25699d7bf0610e05a2221d4",
"sha256:c6de5dbdbb7a0d7d2757f4389cc00e8f6eb3c49e1772378967a12cfcf2cfe098"
"sha256:b8baed19394af85b21755c68c7ec4eac57e8a482ed89cd01cd5d5ff72200fe0f",
"sha256:c39a6fa41bd3ec6fc10064329a664ed3a3ca2e27640a823dc520c682e4433cdb"
],
"version": "==1.6.5"
"version": "==1.6.6"
},
"sphinx-autobuild": {
"hashes": [
@ -230,6 +230,58 @@
}
},
"develop": {
"attrs": {
"hashes": [
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450",
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"
],
"version": "==17.4.0"
},
"coverage": {
"hashes": [
"sha256:d1ee76f560c3c3e8faada866a07a32485445e16ed2206ac8378bd90dadffb9f0",
"sha256:007eeef7e23f9473622f7d94a3e029a45d55a92a1f083f0f3512f5ab9a669b05",
"sha256:17307429935f96c986a1b1674f78079528833410750321d22b5fb35d1883828e",
"sha256:845fddf89dca1e94abe168760a38271abfc2e31863fbb4ada7f9a99337d7c3dc",
"sha256:3f4d0b3403d3e110d2588c275540649b1841725f5a11a7162620224155d00ba2",
"sha256:4c4f368ffe1c2e7602359c2c50233269f3abe1c48ca6b288dcd0fb1d1c679733",
"sha256:f8c55dd0f56d3d618dfacf129e010cbe5d5f94b6951c1b2f13ab1a2f79c284da",
"sha256:cdd92dd9471e624cd1d8c1a2703d25f114b59b736b0f1f659a98414e535ffb3d",
"sha256:2ad357d12971e77360034c1596011a03f50c0f9e1ecd12e081342b8d1aee2236",
"sha256:e9a0e1caed2a52f15c96507ab78a48f346c05681a49c5b003172f8073da6aa6b",
"sha256:eea9135432428d3ca7ee9be86af27cb8e56243f73764a9b6c3e0bda1394916be",
"sha256:700d7579995044dc724847560b78ac786f0ca292867447afda7727a6fbaa082e",
"sha256:66f393e10dd866be267deb3feca39babba08ae13763e0fc7a1063cbe1f8e49f6",
"sha256:5ff16548492e8a12e65ff3d55857ccd818584ed587a6c2898a9ebbe09a880674",
"sha256:d00e29b78ff610d300b2c37049a41234d48ea4f2d2581759ebcf67caaf731c31",
"sha256:87d942863fe74b1c3be83a045996addf1639218c2cb89c5da18c06c0fe3917ea",
"sha256:358d635b1fc22a425444d52f26287ae5aea9e96e254ff3c59c407426f44574f4",
"sha256:81912cfe276e0069dca99e1e4e6be7b06b5fc8342641c6b472cb2fed7de7ae18",
"sha256:079248312838c4c8f3494934ab7382a42d42d5f365f0cf7516f938dbb3f53f3f",
"sha256:b0059630ca5c6b297690a6bf57bf2fdac1395c24b7935fd73ee64190276b743b",
"sha256:493082f104b5ca920e97a485913de254cbe351900deed72d4264571c73464cd0",
"sha256:e3ba9b14607c23623cf38f90b23f5bed4a3be87cbfa96e2e9f4eabb975d1e98b",
"sha256:82cbd3317320aa63c65555aa4894bf33a13fb3a77f079059eb5935eea415938d",
"sha256:9721f1b7275d3112dc7ccf63f0553c769f09b5c25a26ee45872c7f5c09edf6c1",
"sha256:bd4800e32b4c8d99c3a2c943f1ac430cbf80658d884123d19639bcde90dad44a",
"sha256:f29841e865590af72c4b90d7b5b8e93fd560f5dea436c1d5ee8053788f9285de",
"sha256:f3a5c6d054c531536a83521c00e5d4004f1e126e2e2556ce399bef4180fbe540",
"sha256:dd707a21332615108b736ef0b8513d3edaf12d2a7d5fc26cd04a169a8ae9b526",
"sha256:2e1a5c6adebb93c3b175103c2f855eda957283c10cf937d791d81bef8872d6ca",
"sha256:f87f522bde5540d8a4b11df80058281ac38c44b13ce29ced1e294963dd51a8f8",
"sha256:a7cfaebd8f24c2b537fa6a271229b051cdac9c1734bb6f939ccfc7c055689baa",
"sha256:309d91bd7a35063ec7a0e4d75645488bfab3f0b66373e7722f23da7f5b0f34cc",
"sha256:0388c12539372bb92d6dde68b4627f0300d948965bbb7fc104924d715fdc0965",
"sha256:ab3508df9a92c1d3362343d235420d08e2662969b83134f8a97dc1451cbe5e84",
"sha256:43a155eb76025c61fc20c3d03b89ca28efa6f5be572ab6110b2fb68eda96bfea",
"sha256:f98b461cb59f117887aa634a66022c0bd394278245ed51189f63a036516e32de",
"sha256:b6cebae1502ce5b87d7c6f532fa90ab345cfbda62b95aeea4e431e164d498a3d",
"sha256:a4497faa4f1c0fc365ba05eaecfb6b5d24e3c8c72e95938f9524e29dadb15e76",
"sha256:2b4d7f03a8a6632598cbc5df15bbca9f778c43db7cf1a838f4fa2c8599a8691a",
"sha256:1afccd7e27cac1b9617be8c769f6d8a6d363699c9b86820f40c74cfb3328921c"
],
"version": "==4.4.2"
},
"docopt": {
"hashes": [
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
@ -250,6 +302,12 @@
],
"version": "==0.1.1"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
],
"version": "==0.6.0"
},
"prompt-toolkit": {
"hashes": [
"sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
@ -266,6 +324,13 @@
],
"version": "==0.41"
},
"py": {
"hashes": [
"sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
"sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
],
"version": "==1.5.2"
},
"pygments": {
"hashes": [
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
@ -273,6 +338,20 @@
],
"version": "==2.2.0"
},
"pytest": {
"hashes": [
"sha256:b84878865558194630c6147f44bdaef27222a9f153bbd4a08908b16bf285e0b1",
"sha256:53548280ede7818f4dc2ad96608b9f08ae2cc2ca3874f2ceb6f97e3583f25bc4"
],
"version": "==3.3.2"
},
"pytest-cov": {
"hashes": [
"sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec",
"sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d"
],
"version": "==2.5.1"
},
"six": {
"hashes": [
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",

2
pytest.ini 100644
Wyświetl plik

@ -0,0 +1,2 @@
[pytest]
addopts = -rsx --cov=voting tests/ --cov-report=html:_cov

Wyświetl plik

87
tests/conftest.py 100644
Wyświetl plik

@ -0,0 +1,87 @@
"""Fixtures."""
# flake8: noqa
import pytest
from voting.apportionment import adams
from voting.apportionment import dhondt
from voting.apportionment import hagenbach_bischoff
from voting.apportionment import hamilton
from voting.apportionment import huntington_hill
from voting.apportionment import jefferson
from voting.apportionment import sainte_lague
from voting.apportionment import vinton
from voting.apportionment import webster
from voting.diversity import berger_parker
from voting.diversity import general
from voting.diversity import gini_simpson
from voting.diversity import golosov
from voting.diversity import inverse_simpson
from voting.diversity import laakso_taagepera
from voting.diversity import renyi
from voting.diversity import shannon
from voting.diversity import simpson
from voting.proportion import adjusted_loosemore_hanby
from voting.proportion import dhondt as dh # dupe of apportionment
from voting.proportion import gallagher
from voting.proportion import grofman
from voting.proportion import least_square
from voting.proportion import lijphart
from voting.proportion import loosemore_hanby
from voting.proportion import rae
from voting.proportion import regression
from voting.proportion import rose
from voting.proportion import sainte_lague as sl # dupe of apportionment
from voting.quota import droop
from voting.quota import hagenbach_bischoff as hb # dupe of apportionment
from voting.quota import hare
from voting.quota import imperiali
@pytest.fixture(params=[[2560, 3315, 995, 5012]])
def votes(request):
return request.param
@pytest.fixture(params=[20])
def seats(request):
return request.param
@pytest.fixture(params=list(range(4, 50)))
def seats_val(request):
return request.param
@pytest.fixture(params=[[5, 6, 7, 8]])
def seats_list(request):
return request.param
@pytest.fixture(params=[adams, dhondt, hagenbach_bischoff, hamilton,
huntington_hill, jefferson, sainte_lague, vinton, webster
])
def apportionment_method(request):
return request.param
@pytest.fixture(params=[droop, hb, hare, imperiali])
def quota_method(request):
return request.param
@pytest.fixture(params=[droop, hb, hare, imperiali])
def quota_method(request):
return request.param
@pytest.fixture(params=[adjusted_loosemore_hanby, dh, gallagher, grofman,
least_square, lijphart, loosemore_hanby, rae, regression, rose, sl
])
def proportion_method(request):
return request.param
@pytest.fixture(params=['seats', 'votes', 'something_else'])
def parties(request):
return request.param
@pytest.fixture(params=[berger_parker, general, gini_simpson, golosov,
inverse_simpson, laakso_taagepera, renyi, shannon, simpson
])
def diversity_method(request):
return request.param
@pytest.fixture(params=[0, 0.5, 1, 2])
def q(request):
return request.param

Wyświetl plik

@ -0,0 +1,11 @@
"""Apportionment method tests."""
# flake8: noqa
import pytest
def test_apportionment_sum(apportionment_method, votes, seats):
assert sum(apportionment_method(votes, seats)) == seats
def test_apportionment_values(apportionment_method, votes, seats_val):
assert sum(apportionment_method(votes, seats_val)) == seats_val

Wyświetl plik

@ -0,0 +1,18 @@
"""Diversity tests."""
# flake8: noqa
import pytest
from voting.diversity import general
from voting.diversity import renyi
def test_diversity_method(diversity_method, votes):
assert isinstance(diversity_method(votes), float)
def test_general_q(votes, q):
assert isinstance(general(votes, q), float)
def test_renyi_q(votes, q):
assert isinstance(renyi(votes, q), float)

Wyświetl plik

@ -0,0 +1,16 @@
"""Proportion tests."""
# flake8: noqa
import pytest
from voting.proportion import grofman
def test_proportion_method(proportion_method, votes, seats_list):
assert proportion_method(votes, seats_list) > 0
def test_grofman_parties(votes, seats_list, parties):
if parties not in ('votes', 'seats'):
with pytest.raises(ValueError):
grofman(votes, seats_list, parties)
else:
assert grofman(votes, seats_list, parties) > 0

Wyświetl plik

@ -0,0 +1,7 @@
"""Quota tests."""
# flake8: noqa
import pytest
def test_quota_method(quota_method, seats):
assert quota_method(100, seats) > 0

Wyświetl plik

@ -18,7 +18,7 @@ def adams(votes, seats):
surplus = int(sum(upper) - seats)
if surplus > 0:
# divisor diffs that would remove another seat to each group
diffs = [1.0 * vote / floor(i + dec)
diffs = [1.0 * vote / max(floor(i + dec), 1)
for i, dec, vote in zip(lower, decs, votes)]
# argsort low to high
divs = [i[0] for i in sorted(enumerate(diffs), key=itemgetter(1))]

Wyświetl plik

@ -1,4 +1,5 @@
"""Measures of diversity."""
from math import exp
from math import log
from voting.util import normalize
@ -17,7 +18,7 @@ def berger_parker(groups):
return max(groups)
def general(groups, q):
def general(groups, q=1):
r"""Calculate the general diversity index.
.. math::
@ -27,6 +28,8 @@ def general(groups, q):
:param list groups: a list of integers representing populations of groups
:param float q: weight value
"""
if q == 1:
return exp(shannon(groups))
groups = normalize(groups)
return sum([g ** q for g in groups]) ** (1.0 / (1 - q))
@ -84,7 +87,7 @@ def laakso_taagepera(groups):
return 1.0 / sum([g ** 2 for g in groups])
def renyi(groups, q=1):
def renyi(groups, q=0):
r"""Calculate the Renyi entropy.
.. math::
@ -95,6 +98,8 @@ def renyi(groups, q=1):
:param float q: weight value
"""
if q == 1:
return shannon(groups)
groups = normalize(groups)
return 1.0 / (1 - q) * log(sum([g ** q for g in groups]))