kopia lustrzana https://github.com/crflynn/voting
initial commit
commit
4f29802172
|
@ -0,0 +1,28 @@
|
|||
# pytest
|
||||
.cache
|
||||
|
||||
# coverage
|
||||
.coverage
|
||||
.coverage.*
|
||||
_cov
|
||||
|
||||
# python
|
||||
__pycache__
|
||||
*.pyc
|
||||
|
||||
# packaging
|
||||
*.egg-info
|
||||
build/
|
||||
dist/
|
||||
|
||||
# tox
|
||||
.tox
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# docs
|
||||
_build
|
||||
|
||||
# macosx
|
||||
.DS_Store
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Christopher Flynn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,17 @@
|
|||
[[source]]
|
||||
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
|
||||
[packages]
|
||||
|
||||
sphinx = "*"
|
||||
sphinx-autobuild = "*"
|
||||
sphinx-rtd-theme = "*"
|
||||
|
||||
|
||||
[dev-packages]
|
||||
|
||||
ptpython = "*"
|
|
@ -0,0 +1,291 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9ac7ae345861a62cb069f25af526478a0d6ad267299653f8ff51a35e4afc0abb"
|
||||
},
|
||||
"host-environment-markers": {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.6.3",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "x86_64",
|
||||
"platform_python_implementation": "CPython",
|
||||
"platform_release": "16.7.0",
|
||||
"platform_system": "Darwin",
|
||||
"platform_version": "Darwin Kernel Version 16.7.0: Mon Nov 13 21:56:25 PST 2017; root:xnu-3789.72.11~1/RELEASE_X86_64",
|
||||
"python_full_version": "3.6.3",
|
||||
"python_version": "3.6",
|
||||
"sys_platform": "darwin"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:2eef172f44e8d301d25aff8068fddd65f767a3f04b5f15b0f4922f113aa1c732",
|
||||
"sha256:37cdcb9e9954ed60912ebc1ca12a9d12178c26637abdf124e3cde2341c257fe0"
|
||||
],
|
||||
"version": "==0.7.10"
|
||||
},
|
||||
"argh": {
|
||||
"hashes": [
|
||||
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
|
||||
"sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65"
|
||||
],
|
||||
"version": "==0.26.2"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:f20b2acd44f587988ff185d8949c3e208b4b3d5d20fcab7d91fe481ffa435528",
|
||||
"sha256:6007daf714d0cd5524bbe436e2d42b3c20e68da66289559341e48d2cd6d25811"
|
||||
],
|
||||
"version": "==2.5.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:244be0d93b71e93fc0a0a479862051414d0e00e16435707e5bf5000f92e04694",
|
||||
"sha256:5ec74291ca1136b40f0379e1128ff80e866597e4e2c1e755739a913bbc3613c0"
|
||||
],
|
||||
"version": "==2017.11.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6",
|
||||
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274"
|
||||
],
|
||||
"version": "==0.14"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
|
||||
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
|
||||
],
|
||||
"version": "==2.6"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:6ebdc9e0ad188f9d1b2cdd9bc59cbe42bf931875e829e7a595e6b3abdc05cdfb",
|
||||
"sha256:0ab2c62b87987e3252f89d30b7cedbec12a01af9274af9ffa48108f2c13c6062"
|
||||
],
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"livereload": {
|
||||
"hashes": [
|
||||
"sha256:5ed6506f5d526ee712da9f3739c27714e6f3376f3e481728d298efceae0ec83a",
|
||||
"sha256:422de10d7ea9467a1ba27cbaffa84c74b809d96fb1598d9de4b9b676adf35e2c"
|
||||
],
|
||||
"version": "==2.5.1"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
|
||||
],
|
||||
"version": "==1.0"
|
||||
},
|
||||
"pathtools": {
|
||||
"hashes": [
|
||||
"sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"
|
||||
],
|
||||
"version": "==0.1.2"
|
||||
},
|
||||
"port-for": {
|
||||
"hashes": [
|
||||
"sha256:b16a84bb29c2954db44c29be38b17c659c9c27e33918dec16b90d375cc596f1c"
|
||||
],
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
|
||||
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:80af0f3008046b9975242012a985f04c5df1f01eed4ec1633d56cc47a75a6a48",
|
||||
"sha256:feb2365914948b8620347784b6b6da356f31c9d03560259070b2f30cff3d469d",
|
||||
"sha256:59707844a9825589878236ff2f4e0dc9958511b7ffaae94dc615da07d4a68d33",
|
||||
"sha256:d0ef5ef55ed3d37854320d4926b04a4cb42a2e88f71da9ddfdacfde8e364f027",
|
||||
"sha256:c41c62827ce9cafacd6f2f7018e4f83a6f1986e87bfd000b8cfbd4ab5da95f1a",
|
||||
"sha256:8cc90340159b5d7ced6f2ba77694d946fc975b09f1a51d93f3ce3bb399396f94",
|
||||
"sha256:dd2e4ca6ce3785c8dd342d1853dd9052b19290d5bf66060846e5dc6b8d6667f7",
|
||||
"sha256:699d18a2a56f19ee5698ab1123bbcc1d269d061996aeb1eda6d89248d3542b82",
|
||||
"sha256:fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
|
||||
],
|
||||
"version": "==2017.3"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f",
|
||||
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736",
|
||||
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269",
|
||||
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
|
||||
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
|
||||
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
|
||||
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
|
||||
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
|
||||
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
|
||||
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
|
||||
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
|
||||
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
|
||||
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
|
||||
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7"
|
||||
],
|
||||
"version": "==3.12"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
|
||||
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
|
||||
],
|
||||
"version": "==2.18.4"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89",
|
||||
"sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128"
|
||||
],
|
||||
"version": "==1.2.1"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:fdf77f4f30d84a314c797d67fe7d1b46665e6c48a25699d7bf0610e05a2221d4",
|
||||
"sha256:c6de5dbdbb7a0d7d2757f4389cc00e8f6eb3c49e1772378967a12cfcf2cfe098"
|
||||
],
|
||||
"version": "==1.6.5"
|
||||
},
|
||||
"sphinx-autobuild": {
|
||||
"hashes": [
|
||||
"sha256:e60aea0789cab02fa32ee63c7acae5ef41c06f1434d9fd0a74250a61f5994692",
|
||||
"sha256:66388f81884666e3821edbe05dd53a0cfb68093873d17320d0610de8db28c74e"
|
||||
],
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"sphinx-rtd-theme": {
|
||||
"hashes": [
|
||||
"sha256:62ee4752716e698bad7de8a18906f42d33664128eea06c46b718fc7fbd1a9f5c",
|
||||
"sha256:2df74b8ff6fae6965c527e97cca6c6c944886aae474b490e17f92adfbe843417"
|
||||
],
|
||||
"version": "==0.2.4"
|
||||
},
|
||||
"sphinxcontrib-websupport": {
|
||||
"hashes": [
|
||||
"sha256:f4932e95869599b89bf4f80fc3989132d83c9faa5bf633e7b5e0c25dffb75da2",
|
||||
"sha256:7a85961326aa3a400cd4ad3c816d70ed6f7c740acd7ce5d78cd0a67825072eb9"
|
||||
],
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:92b7ca81e18ba9ec3031a7ee73d4577ac21d41a0c9b775a9182f43301c3b5f8e",
|
||||
"sha256:b36298e9f63f18cad97378db2222c0e0ca6a55f6304e605515e05a25483ed51a",
|
||||
"sha256:ab587996fe6fb9ce65abfda440f9b61e4f9f2cf921967723540679176915e4c3",
|
||||
"sha256:5ef073ac6180038ccf99411fe05ae9aafb675952a2c8db60592d5daf8401f803",
|
||||
"sha256:6d14e47eab0e15799cf3cdcc86b0b98279da68522caace2bd7ce644287685f0a"
|
||||
],
|
||||
"version": "==4.5.3"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
|
||||
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
|
||||
],
|
||||
"version": "==1.22"
|
||||
},
|
||||
"watchdog": {
|
||||
"hashes": [
|
||||
"sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162"
|
||||
],
|
||||
"version": "==0.8.3"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"docopt": {
|
||||
"hashes": [
|
||||
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
|
||||
],
|
||||
"version": "==0.6.2"
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:d795f2c2e659f5ea39a839e5230d70a0b045d0daee7ca2403568d8f348d0ad89",
|
||||
"sha256:d6e799d04d1ade9459ed0f20de47c32f2285438956a677d083d3c98def59fa97"
|
||||
],
|
||||
"version": "==0.11.1"
|
||||
},
|
||||
"parso": {
|
||||
"hashes": [
|
||||
"sha256:a7bb86fe0844304869d1c08e8bd0e52be931228483025c422917411ab82d628a",
|
||||
"sha256:5815f3fe254e5665f3c5d6f54f086c2502035cb631a91341591b5a564203cffb"
|
||||
],
|
||||
"version": "==0.1.1"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
|
||||
"sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381",
|
||||
"sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"
|
||||
],
|
||||
"version": "==1.0.15"
|
||||
},
|
||||
"ptpython": {
|
||||
"hashes": [
|
||||
"sha256:55d7cfad50a096f5922c4fdf8cea068a7ec9257418064b437c617ff2f120f81a",
|
||||
"sha256:816da300f620fb88ba97c7962062c8c178d6693b1db19c184660156b1af91bdc",
|
||||
"sha256:a78b27a85c5dbe9d89376e7f3aa70a9d8fa15cb45ee5f73a3cc3963b9b528ac1"
|
||||
],
|
||||
"version": "==0.41"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
|
||||
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"wcwidth": {
|
||||
"hashes": [
|
||||
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c",
|
||||
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"
|
||||
],
|
||||
"version": "==0.1.7"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
Release History
|
||||
---------------
|
||||
|
||||
0.1.0 (2018-01-07)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* First release.
|
||||
* Various quotas, disproportionality measures, and apportionment functions
|
|
@ -0,0 +1,23 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = voting
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
livehtml:
|
||||
sphinx-autobuild -b html $(SOURCEDIR) $(BUILDDIR)/html
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,30 @@
|
|||
Apportionments
|
||||
==============
|
||||
|
||||
The :py:mod:`apportionment` module provides functions for apportioning seats
|
||||
according to lists of votes.
|
||||
|
||||
* :py:func:`voting.apportionment.adams`
|
||||
* :py:func:`voting.apportionment.dhondt`
|
||||
* :py:func:`voting.apportionment.hagenbach_bischoff`
|
||||
* :py:func:`voting.apportionment.hamilton`
|
||||
* :py:func:`voting.apportionment.huntington_hill`
|
||||
* :py:func:`voting.apportionment.jefferson`
|
||||
* :py:func:`voting.apportionment.vinton`
|
||||
* :py:func:`voting.apportionment.webster`
|
||||
|
||||
.. autofunction:: voting.apportionment.adams
|
||||
|
||||
.. autofunction:: voting.apportionment.dhondt
|
||||
|
||||
.. autofunction:: voting.apportionment.hagenbach_bischoff
|
||||
|
||||
.. autofunction:: voting.apportionment.hamilton
|
||||
|
||||
.. autofunction:: voting.apportionment.huntington_hill
|
||||
|
||||
.. autofunction:: voting.apportionment.jefferson
|
||||
|
||||
.. autofunction:: voting.apportionment.vinton
|
||||
|
||||
.. autofunction:: voting.apportionment.webster
|
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# flake8: noqa
|
||||
#
|
||||
# voting documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sat Jan 6 19:27:38 2018.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
import voting
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = voting.__title__
|
||||
copyright = voting.__docs_copyright__
|
||||
author = voting.__author__
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = ''
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = ''
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
import sphinx_rtd_theme
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'votingdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'voting.tex', 'voting Documentation',
|
||||
'Christopher Flynn', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'voting', 'voting Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'voting', 'voting Documentation',
|
||||
author, 'voting', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
|
@ -0,0 +1,28 @@
|
|||
.. voting documentation master file, created by
|
||||
sphinx-quickstart on Sat Jan 6 19:27:38 2018.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to voting's documentation!
|
||||
==================================
|
||||
|
||||
This is a small module that provides simple functions related to measures of
|
||||
disproportionality, election quotas, and electoral apportionment.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
apportionment
|
||||
measure
|
||||
quota
|
||||
notes
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
|
@ -0,0 +1,36 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=voting
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,39 @@
|
|||
Measures
|
||||
========
|
||||
|
||||
The :py:mod:`measure` module contains functions for measuring
|
||||
disproportionality in electoral systems.
|
||||
|
||||
* :py:func:`voting.measure.adjusted_loosemore_hanby`
|
||||
* :py:func:`voting.measure.dhondt`
|
||||
* :py:func:`voting.measure.gallagher`
|
||||
* :py:func:`voting.measure.grofman`
|
||||
* :py:func:`voting.measure.least_square`
|
||||
* :py:func:`voting.measure.lijphart`
|
||||
* :py:func:`voting.measure.loosemore_hanby`
|
||||
* :py:func:`voting.measure.rae`
|
||||
* :py:func:`voting.measure.regression`
|
||||
* :py:func:`voting.measure.rose`
|
||||
* :py:func:`voting.measure.saint_lague`
|
||||
|
||||
.. autofunction:: voting.measure.adjusted_loosemore_hanby
|
||||
|
||||
.. autofunction:: voting.measure.dhondt
|
||||
|
||||
.. autofunction:: voting.measure.gallagher
|
||||
|
||||
.. autofunction:: voting.measure.grofman
|
||||
|
||||
.. autofunction:: voting.measure.least_square
|
||||
|
||||
.. autofunction:: voting.measure.lijphart
|
||||
|
||||
.. autofunction:: voting.measure.loosemore_hanby
|
||||
|
||||
.. autofunction:: voting.measure.rae
|
||||
|
||||
.. autofunction:: voting.measure.regression
|
||||
|
||||
.. autofunction:: voting.measure.rose
|
||||
|
||||
.. autofunction:: voting.measure.saint_lague
|
|
@ -0,0 +1,21 @@
|
|||
Release Notes
|
||||
=============
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Voting is an open source python package.
|
||||
|
||||
If you have additional content
|
||||
that you think would be suitable for this package, please let me know on this
|
||||
project's `GitHub page <https://github.com/crflynn/voting>`_.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
.. include:: ../LICENSE.txt
|
||||
:literal:
|
||||
|
||||
|
||||
|
||||
.. include:: ../HISTORY.rst
|
|
@ -0,0 +1,18 @@
|
|||
Quotas
|
||||
======
|
||||
|
||||
The :py:mod:`quota` module contains functions for calculating quotas used to
|
||||
elect candidates in single transferrable vote elections.
|
||||
|
||||
* :py:func:`voting.quota.droop`
|
||||
* :py:func:`voting.quota.hagenbach_bischoff`
|
||||
* :py:func:`voting.quota.hare`
|
||||
* :py:func:`voting.quota.imperiali`
|
||||
|
||||
.. autofunction:: voting.quota.droop
|
||||
|
||||
.. autofunction:: voting.quota.hagenbach_bischoff
|
||||
|
||||
.. autofunction:: voting.quota.hare
|
||||
|
||||
.. autofunction:: voting.quota.imperiali
|
|
@ -0,0 +1,22 @@
|
|||
"""Module level accessible objects."""
|
||||
from voting.__version__ import __version__
|
||||
from voting.__version__ import __description__
|
||||
from voting.__version__ import __url__
|
||||
from voting.__version__ import __title__
|
||||
from voting.__version__ import __author__
|
||||
from voting.__version__ import __author_email__
|
||||
from voting.__version__ import __license__
|
||||
from voting.__version__ import __copyright__
|
||||
from voting.__version__ import __docs_copyright__
|
||||
|
||||
__all__ = (
|
||||
__version__,
|
||||
__description__,
|
||||
__url__,
|
||||
__title__,
|
||||
__author__,
|
||||
__author_email__,
|
||||
__license__,
|
||||
__copyright__,
|
||||
__docs_copyright__,
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
"""Version information."""
|
||||
__title__ = "voting"
|
||||
__description__ = "Voting and election related functions."
|
||||
__url__ = "https://github.com/crflynn/stochastic"
|
||||
__version__ = "0.1.0"
|
||||
__author__ = "Christopher Flynn"
|
||||
__author_email__ = "crf204@gmail.com"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright 2018 Christopher Flynn"
|
||||
__docs_copyright__ = "2018 Christopher Flynn"
|
|
@ -0,0 +1,103 @@
|
|||
"""Apportionment methods."""
|
||||
from math import ceil
|
||||
from math import modf
|
||||
from operator import itemgetter
|
||||
|
||||
|
||||
def adams(votes, seats):
|
||||
"""Apportion seats using the Adams method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def dhondt(votes, seats):
|
||||
"""Apportion seats using the D'Hondt method.
|
||||
|
||||
Identical to the Jefferson method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
return jefferson(votes, seats)
|
||||
|
||||
|
||||
def hagenbach_bischoff(votes, seats):
|
||||
"""Apportion seats using the Hagenbach-Bischoff method.
|
||||
|
||||
Identical to the Jefferson method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
return jefferson(votes, seats)
|
||||
|
||||
|
||||
def hamilton(votes, seats):
|
||||
"""Apportion seats using the Hamilton method.
|
||||
|
||||
Known also as the Vinton method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
divisor = 1.0 * sum(votes) / seats
|
||||
decs, ints = zip(*[modf(1.0 * v / divisor) for v in votes])
|
||||
ints = list(ints)
|
||||
unallocated = int(seats - sum(ints))
|
||||
leftovers = \
|
||||
[i[0] for i in sorted(enumerate(decs), key=itemgetter(1))][::-1]
|
||||
for k in range(unallocated):
|
||||
ints[leftovers[k]] += 1
|
||||
return ints
|
||||
|
||||
|
||||
def huntington_hill(votes, seats):
|
||||
"""Apportion seats using the Huntington-Hill method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def jefferson(votes, seats):
|
||||
"""Apportion seats using the Jefferson method.
|
||||
|
||||
Known also as the D'Hondt method or Hagenbach-Bischoff method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
divisor = 1.0 * sum(votes) / seats
|
||||
decs, ints = zip(*[modf(1.0 * v / divisor) for v in votes])
|
||||
ints = list(ints)
|
||||
unallocated = int(seats - sum(ints))
|
||||
diffs = [1.0 * vote / ceil(i + dec)
|
||||
for i, dec, vote in zip(ints, decs, votes)]
|
||||
divs = [i[0] for i in sorted(enumerate(diffs), key=itemgetter(1))][::-1]
|
||||
for k in range(unallocated):
|
||||
ints[divs[k]] += 1
|
||||
return ints
|
||||
|
||||
|
||||
def vinton(votes, seats):
|
||||
"""Apportion seats using the Vinton method.
|
||||
|
||||
Identical to the Hamilton method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
return hamilton(votes, seats)
|
||||
|
||||
|
||||
def webster(votes, seats):
|
||||
"""Apportion seats using the Webster method.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param int seats: the number of seats to apportion
|
||||
"""
|
||||
pass
|
|
@ -0,0 +1,192 @@
|
|||
"""Measures of disproportionality."""
|
||||
from math import sqrt
|
||||
|
||||
|
||||
def normalize(values):
|
||||
"""Normalize a list of values."""
|
||||
total = sum(values)
|
||||
return [1.0 * value / total for value in values]
|
||||
|
||||
|
||||
def adjusted_loosemore_hanby(votes, seats, parties='votes'):
|
||||
r"""Calculate the adjusted Loosemore-Hanby index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
N \sum_{i=1}^n |v_i - s_i|
|
||||
|
||||
where N is :math:`\sum_{i=1}^n v_i` if ``parties == 'votes'`` or
|
||||
:math:`\sum_{i=1}^n s_i` if ``parties == 'seats'``.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
:param str parties: ``votes`` or ``seats`` to use to calculate the
|
||||
effective number of parties
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return grofman(votes, seats, parties)
|
||||
|
||||
|
||||
def dhondt(votes, seats):
|
||||
r"""Calculate the D'Hondt index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\max \frac{s_i}{v_i}
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return max([1.0 * s / v for v, s in zip(votes, seats)])
|
||||
|
||||
|
||||
def gallagher(votes, seats):
|
||||
r"""Calculate the Gallagher index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\sqrt{\frac{1}{2} \sum_{i=1}^n (v_i - s_i)^2}
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return sqrt(1.0 / 2) * least_square(votes, seats)
|
||||
|
||||
|
||||
def grofman(votes, seats, parties='votes'):
|
||||
r"""Calculate the Grofman index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
N \sum_{i=1}^n |v_i - s_i|
|
||||
|
||||
where N is :math:`\sum_{i=1}^n v_i^2` if ``parties == 'votes'`` or
|
||||
:math:`\sum_{i=1}^n s_i^2` if ``parties == 'seats'``.
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
:param str parties: ``votes`` or ``seats`` to use to calculate the
|
||||
effective number of parties
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
if parties == 'votes':
|
||||
n = sum([v ** 2 for v in votes])
|
||||
elif parties == 'seats':
|
||||
n = sum([s ** 2 for s in seats])
|
||||
else:
|
||||
raise ValueError("Parties argument must be either votes or seats.")
|
||||
|
||||
return n * sum([abs(v - s) for v, s in zip(votes, seats)])
|
||||
|
||||
|
||||
def least_square(votes, seats):
|
||||
r"""Calculate the least squares index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\sqrt{\sum_{i=1}^n (v_i - s_i)^2}
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return sqrt(sum([(v - s) ** 2 for v, s in zip(votes, seats)]))
|
||||
|
||||
|
||||
def lijphart(votes, seats):
|
||||
r"""Calculate the Lijphart index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\max | v_i - s_i |
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return max([abs(v - s) for v, s in zip(votes, seats)])
|
||||
|
||||
|
||||
def loosemore_hanby(votes, seats):
|
||||
r"""Calculate Loosemore-Hanby index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{1}{2} \sum_{i=1}^n |v_i - s_i|
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return 1.0 / 2 * sum([abs(v - s) for v, s in zip(votes, seats)])
|
||||
|
||||
|
||||
def rae(votes, seats):
|
||||
r"""Calculate Rae's index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{1}{n} \sum_{i=1}^n |v_i - s_i|
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return 1.0 / len(votes) * sum([abs(v - s) for v, s in zip(votes, seats)])
|
||||
|
||||
|
||||
def regression(votes, seats):
|
||||
r"""Calculate the regression index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{\sum_{i=1}^n v_i s_i}{\sum_{i=1}^n v_i^2}
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
num = sum([v * s for v, s in zip(votes, seats)])
|
||||
denom = sum([v ** 2 for v in votes])
|
||||
return 1.0 * num / denom
|
||||
|
||||
|
||||
def rose(votes, seats):
|
||||
r"""Calculate the Rose index of proportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
100 - \frac{1}{2} \sum_{i=1}^n |v_i - s_i|
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return 100 - loosemore_hanby(votes, seats)
|
||||
|
||||
|
||||
def saint_lague(votes, seats):
|
||||
r"""Calculate the Saint-Lague index of disproportionality.
|
||||
|
||||
.. math::
|
||||
|
||||
\sum_{i=1}^n \frac{(v_i - s_i)^2}{v_i}
|
||||
|
||||
:param list votes: a list of vote counts
|
||||
:param list seats: a list of seat counts
|
||||
"""
|
||||
votes = normalize(votes)
|
||||
seats = normalize(seats)
|
||||
return sum(1.0 / v * (v - s) ** 2 for v, s in zip(votes, seats))
|
|
@ -0,0 +1,45 @@
|
|||
"""Quota calculations."""
|
||||
|
||||
|
||||
def droop(votes, seats):
|
||||
r"""Calculate the Droop quota.
|
||||
|
||||
:math:`\frac{votes}{seats + 1} + 1`
|
||||
|
||||
:param int votes: the number of votes
|
||||
:param int seats: the number of seats
|
||||
"""
|
||||
return int(1.0 * votes / (seats + 1) + 1)
|
||||
|
||||
|
||||
def hagenbach_bischoff(votes, seats):
|
||||
r"""Calculate the Hagenbach-Bischoff quota.
|
||||
|
||||
:math:`\frac{votes}{seats + 1}`
|
||||
|
||||
:param int votes: the number of votes
|
||||
:param int seats: the number of seats
|
||||
"""
|
||||
return 1.0 * votes / (seats + 1)
|
||||
|
||||
|
||||
def hare(votes, seats):
|
||||
r"""Calculate the Hare quota.
|
||||
|
||||
:math:`\frac{votes}{seats}`
|
||||
|
||||
:param int votes: the number of votes
|
||||
:param int seats: the number of seats
|
||||
"""
|
||||
return 1.0 * votes / seats
|
||||
|
||||
|
||||
def imperiali(votes, seats):
|
||||
r"""Calculate the Imperiali quota.
|
||||
|
||||
:math:`\frac{votes}{seats + 2}`
|
||||
|
||||
:param int votes: the number of votes
|
||||
:param int seats: the number of seats
|
||||
"""
|
||||
return 1.0 * votes / (seats + 2)
|
Ładowanie…
Reference in New Issue