# -*- coding: utf-8 -*-
from setuptools import setup

modules = \
['__init__']
install_requires = \
['numpy>=1.17.0,<2.0.0']

setup_kwargs = {
    'name': 'polyagamma',
    'version': '1.1.0b3',
    'description': 'Efficiently generate samples from the Polya-Gamma distribution using a NumPy/SciPy compatible interface.',
    'long_description': '# polya-gamma\n[![PyPI - Wheel][4]](https://pypi.org/project/polyagamma/#files)\n[![PyPI][5]](https://pypi.org/project/polyagamma/#history)\n[![PyPI - License][6]](https://github.com/zoj613/polyagamma/blob/main/LICENSE)\n[![CircleCI][7]](https://circleci.com/gh/zoj613/polyagamma/)\n[![Codecov][8]](https://codecov.io/gh/zoj613/polyagamma/)\n[![PyPI - Downloads][9]](https://pypistats.org/packages/polyagamma)\n\n\nEfficiently generate samples from the Polya-Gamma distribution using a NumPy/SciPy compatible interface.\n![densities](./scripts/densities.svg)\n\n\n## Features\n- `polyagamma` is written in C and optimized for performance.\n- Very light and easy to install (pre-built wheels).\n- It is flexible and allows the user to sample using one of 4 available methods.\n- Input parameters can be scalars, arrays or both; allowing for easy generation\nof multi-dimensional samples without specifying the size.\n- Random number generation is thread safe.\n- The functional API resembles that of common numpy/scipy functions, therefore making it easy to plugin to\nexisting libraries.\n\n\n## Dependencies\n- Numpy >= 1.17 \n\n\n## Installation\nTo get the latest version of the package, one can install it by downloading the wheel/source distribution \nfrom the [releases][3] page, or using `pip` with the following shell command:\n```shell\n$ pip install polyagamma\n```\nTo install the latest pre-release version, use:\n```shell\n$ pip install --pre -U polyagamma\n```\nAlternatively, once can install from source by cloning the repo. This requires an installation of [poetry][2]\nand the following shell commands:\n```shell\n$ git clone https://github.com/zoj613/polya-gamma.git\n$ cd polya-gamma/\n$ poetry install\n# add package to python\'s path\n$ export PYTHONPATH=$PWD:$PYTHONPATH \n```\n\n## Example\n\n### Python\n\n```python\nimport numpy as np\nfrom polyagamma import polyagamma\n\n# generate a PG(1, 0) sample\no = polyagamma()\n\n# Get a 5 by 10 array of PG(1, 2) variates.\no = polyagamma(z=2, size=(5, 10))\n\n# Pass sequences as input. Numpy\'s broadcasting rules apply here.\nh = [[1.5, 2, 0.75, 4, 5],\n     [9.5, 8, 7, 6, 0.9]]\no = polyagamma(h, -2.5)\n\n# Pass an output array\nout = np.empty(5)\npolyagamma(out=out)\nprint(out)\n\n# one can choose a sampling method from {devroye, alternate, gamma, saddle}.\n# If not given, the default behaviour is a hybrid sampler that picks a method\n# based on the parameter values.\no = polyagamma(method="saddle")\n\n# one can also use an existing instance of `numpy.random.Generator` as a parameter.\n# This is useful to reproduce samples generated via a given seed.\nrng = np.random.default_rng(12345)\no = polyagamma(random_state=rng)\n\n# If one is using a `numpy.random.RandomState` instance instead of the `Generator`\n# class, the object\'s underlying bitgenerator can be passed as the value of random_state\nbit_gen = np.random.RandomState(12345)._bit_generator\no = polyagamma(random_state=bit_gen)\n\n# When passing a large input array for the shape parameter `h`, parameter value\n# validation checks can be disabled to avoid some overhead, which may boost performance.\nlarge_h = np.ones(1000000)\no = polyagamma(large_h, disable_checks=True)\n```\n### C\nFor an example of how to use `polyagamma` in a C program, see [here][1].\n\n\n## Benchmarks\n\nBelow are runtime plots of 20000 samples generated for various values of `h` \nand `z`, using each method. We restrict `h` to integer values to accomodate the \n`devroye` method, which cannot be used for non-integer `h`. The version of the\npackage used to generate them is `v1.1.0-beta.3`.\n\n![](./scripts/perf_methods_0.0.svg) | ![](./scripts/perf_methods_2.5.svg)\n| --- | --- |\n\n![](./scripts/perf_methods_5.0.svg) | ![](./scripts/perf_methods_10.0.svg)\n| --- | --- |\n\nGenerally:\n- The `gamma` method is slowest and should be avoided in cases where speed is paramount.\n- For `h > 15`, the `saddle` method is the fastest for any value of `z`.\n- For `z <= 1` and integer `h <= 15`, the `devroye` method is the most efficient.\n- For `z > 1` and integer/non-integer `h <= 15`, the `alternate` method is the most efficient.\n- For `h > 50` (or any value large enough), the normal approximation to the distribution is \nfastest (not reported in the above plot but it is around 10 times faster than the `saddle` \nmethod and also equally accurate).\n\nTherefore, we devise a "hybrid/default" sampler that picks a sampler based on the above guidelines.\n\nWe also benchmark the hybrid sampler runtime with the sampler found in the `pypolyagamma` \npackage (version `1.2.3`). The version of NumPy we use is `1.19.4`. We use the `pgdrawv` \nfunction which takes arrays as input. Below are runtime plots of 20000 samples for each \nvalue of `h` and `z`. Values of `h` range from 0.1 to 60, while `z` is set to 0, 2.5, 5, and 10.\n![](./scripts/perf_samplers_0.0.svg) | ![](./scripts/perf_samplers_2.5.svg)\n| --- | --- |\n\n![](./scripts/perf_samplers_5.0.svg) | ![](./scripts/perf_samplers_10.0.svg)\n| --- | --- |\n\nIt can be seen that when generating many samples at once for any given combination of \nparameters, `polyagamma` outperforms the `pypolyagamma` package. The exception is when \n`h < 1`. We rely on the `saddle` method to generate samples when the shape parameter is \nvery small, which is not very efficient for such values. For values of `h` larger than 50, \nwe use the normal approximation, which explains the large dip in runtime past `h=50`. \nIt is also worth noting that the `pypolygamma` package is on average faster than ours at \ngenerating exactly one sample from the distribution. This is mainly due to the \noverhead introduced by creating the bitgenerator + acquiring/releasing the thread lock + \ndoing parameter validation checks at every call to the function. This overhead can \nsomewhat be mitigated by passing in a random generator instance at every call to \nthe `polyagamma` function. For example, on an `iPython` session:\n```ipynb\nIn [4]: %timeit polyagamma()\n94.6 µs ± 1.25 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\nIn [9]: %timeit polyagamma(random_state=rng)\n4.95 µs ± 15.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n```\n\n\nTo generate the above plots locally, run `python scripts/benchmark.py --size=<some size> --z=<z value>`.\nNote that the runtimes may differ  than the ones reported here, depending on the machine this script \nis ran on.\n\n\n## Contributing\nAll contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome.\n\nTo submit a PR, follow the steps below:\n1) Fork the repo.\n2) Setup the dev environment with `poetry install`. All dependencies will be installed.\n3) Start writing your changes, including unittests.\n3) Once finished, run `make install` to build the project with the new changes.\n4) Once build is successful, run tests to make sure they all pass with `make test`.\n5) Once finished, you can submit a PR for review.\n\n\n## References\n- Luc Devroye. "On exact simulation algorithms for some distributions related to Jacobi theta functions." Statistics & Probability Letters, Volume 79, Issue 21, (2009): 2251-2259.\n- Polson, Nicholas G., James G. Scott, and Jesse Windle. "Bayesian inference for logistic models using Pólya–Gamma latent variables." Journal of the American statistical Association 108.504 (2013): 1339-1349.\n- J. Windle, N. G. Polson, and J. G. Scott. "Improved Polya-gamma sampling". Technical Report, University of Texas at Austin, 2013b.\n- Windle, Jesse, Nicholas G. Polson, and James G. Scott. "Sampling Polya-Gamma random variates: alternate and approximate techniques." arXiv preprint arXiv:1405.0506 (2014)\n- Windle, J. (2013). Forecasting high-dimensional, time-varying variance-covariance matrices with high-frequency data and sampling Pólya-Gamma random variates for posterior distributions derived from logistic likelihoods.(PhD thesis). Retrieved from http://hdl.handle.net/2152/21842 .\n\n\n[1]: ./examples/c_polyagamma.c\n[2]: https://python-poetry.org/docs/pyproject/\n[3]: https://github.com/zoj613/polyagamma/releases\n[4]: https://img.shields.io/pypi/wheel/polyagamma?style=flat-square\n[5]: https://img.shields.io/github/v/release/zoj613/polyagamma?include_prereleases&style=flat-square\n[6]: https://img.shields.io/pypi/l/polyagamma?style=flat-square\n[7]: https://img.shields.io/circleci/build/github/zoj613/polyagamma/main?style=flat-square\n[8]: https://img.shields.io/codecov/c/github/zoj613/polyagamma?style=flat-square\n[9]: https://img.shields.io/pypi/dm/polyagamma?style=flat-square\n',
    'author': 'Zolisa Bleki',
    'author_email': None,
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/zoj613/polyagamma/',
    'py_modules': modules,
    'install_requires': install_requires,
    'python_requires': '>=3.6,<4.0',
}
from build import *
build(setup_kwargs)

setup(**setup_kwargs)
