pull/4/head
crflynn 2018-01-06 20:55:14 -05:00
commit 4f29802172
19 zmienionych plików z 1114 dodań i 0 usunięć

28
.gitignore vendored 100644
Wyświetl plik

@ -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
HISTORY.rst 100644
Wyświetl plik

21
LICENSE.txt 100644
Wyświetl plik

@ -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.

17
Pipfile 100644
Wyświetl plik

@ -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 = "*"

291
Pipfile.lock wygenerowano 100644
Wyświetl plik

@ -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"
}
}
}

8
README.rst 100644
Wyświetl plik

@ -0,0 +1,8 @@
Release History
---------------
0.1.0 (2018-01-07)
~~~~~~~~~~~~~~~~~~
* First release.
* Various quotas, disproportionality measures, and apportionment functions

23
docs/Makefile 100644
Wyświetl plik

@ -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)

Wyświetl plik

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

182
docs/conf.py 100644
Wyświetl plik

@ -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'),
]

28
docs/index.rst 100644
Wyświetl plik

@ -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`

36
docs/make.bat 100644
Wyświetl plik

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

39
docs/measure.rst 100644
Wyświetl plik

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

21
docs/notes.rst 100644
Wyświetl plik

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

18
docs/quota.rst 100644
Wyświetl plik

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

22
voting/__init__.py 100644
Wyświetl plik

@ -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__,
)

Wyświetl plik

@ -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"

Wyświetl plik

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

192
voting/measure.py 100644
Wyświetl plik

@ -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))

45
voting/quota.py 100644
Wyświetl plik

@ -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)