# -*- coding: utf-8 -*-
from distutils.core import setup

packages = \
['aiger_coins']

package_data = \
{'': ['*']}

install_requires = \
['attrs>=19.3,<20.0',
 'bidict>=0.18.3,<0.19.0',
 'funcy>=1.13,<2.0',
 'py-aiger-bv>=1.3.3,<2.0.0',
 'py-aiger>=3.6,<4.0']

extras_require = \
{'bdd': ['py-aiger-bdd>=0.2.6,<0.3.0'], 'sat': ['py-aiger-sat>=1.0,<2.0']}

setup_kwargs = {
    'name': 'py-aiger-coins',
    'version': '1.2.4',
    'description': 'Library for creating circuits that encode discrete distributions.',
    'long_description': '[![Build Status](https://cloud.drone.io/api/badges/mvcisback/py-aiger-coins/status.svg)](https://cloud.drone.io/mvcisback/py-aiger-coins)\n[![codecov](https://codecov.io/gh/mvcisback/py-aiger-coins/branch/master/graph/badge.svg)](https://codecov.io/gh/mvcisback/py-aiger-coins)\n[![Updates](https://pyup.io/repos/github/mvcisback/py-aiger-coins/shield.svg)](https://pyup.io/repos/github/mvcisback/py-aiger-coins/)\n\n[![PyPI version](https://badge.fury.io/py/py-aiger-coins.svg)](https://badge.fury.io/py/py-aiger-coins)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\n# py-aiger-coins\nLibrary for creating circuits that encode discrete distributions and\nMarkov Decision Processes. The name comes from the random bit model of\ndrawing from discrete distributions using coin flips.\n\n<!-- markdown-toc start - Don\'t edit this section. Run M-x markdown-toc-refresh-toc -->\n**Table of Contents**\n\n- [py-aiger-coins](#py-aiger-coins)\n- [Install](#install)\n- [Usage](#usage)\n    - [Biased Coins](#biased-coins)\n    - [Distributions on discrete sets](#distributions-on-discrete-sets)\n    - [Distributions and Coins](#distributions-and-coins)\n        - [Manipulating Distributions](#manipulating-distributions)\n    - [Binomial Distributions](#binomial-distributions)\n    - [Markov Decision Processes and Probablistic Circuits](#markov-decision-processes-and-probablistic-circuits)\n\n<!-- markdown-toc end -->\n\n\n# Install\n\nTo install this library run:\n\n`$ pip install py-aiger-coins`\n\nNote that to actually compute probabilities, one needs to install with the bdd option.\n\n`$ pip install py-aiger-coins[bdd]`\n\nFor developers, note that this project uses the\n[poetry](https://poetry.eustace.io/) python package/dependency\nmanagement tool. Please familarize yourself with it and then run:\n\n`$ poetry install`\n\n# Usage\n\nNote this tutorial assumes `py-aiger-bdd` has been installed (see the\nInstall section).\n\n## Biased Coins\n\nWe start by encoding a biased coin and computing its bias. The primary\nentrypoint for modeling coins is the `coin` function.\n\n```python\nfrom fractions import Fraction\n\nimport aiger_coins\n\nbias = Fraction(1, 3)\ncoin1 = aiger_coins.coin(bias)\ncoin2 = aiger_coins.coin((1, 3))  # or just use a tuple.\n\nassert coin1.prob() == coin2.prob() == prob\n```\n\n## Distributions on discrete sets\n\nWe now illustrate how to create a set of mutually exclusive coins that\nrepresent distribution over a finite set. For example, a biased three\nsided dice can be 1-hot encoded with:\n\n```python\ndice = aiger_coins.dist([1, 3, 2], name=\'x\')\ndice = aiger_coins.dist([(1, 6), (3, 6), (2, 6)], name=\'x\')  # equivalent\ndice = aiger_coins.dist([Fraction(1, 6), Fraction(3, 6), Fraction(2, 6)], name=\'x\')  # equivalent\n\nprint(dice.freqs())\n# (Fraction(1, 6), Fraction(1, 2), Fraction(1, 3))\n```\n\nLetting, `⚀ = dice[0]`, `⚁ = dice[1]`, `⚂ = dice[2]`, \n```python\none, two, three = dice[0], dice[1], dice[2]\n```\n\nWe can ask the probability of drawing an element of `{⚀, ⚁}` with:\n\n```python\nassert (one | two).prob() == Fraction(2, 3)\nassert (~three).prob() == Fraction(2, 3)\n```\n\n## Distributions and Coins\n\n`Distribution`s and `Coin`s are really just wrappers around two\n`aiger_bv.UnsignedBVExpr` objects stored in the `expr` and `valid`\nattributes.\n\nThe attributes `expr` and `valid` encode an expression over fair coin\nflips and which coin flips are "valid" respectively. Coins is a\nspecial type of `Distribution` where the expression is a predicate\n(e.g. has one output).\n\nNote that accessing the ith element of a `Distribution` results in a\n`Coin` encoding the probability of drawing that element.\n\n### Manipulating Distributions\n\nIn general `Distribution`s can me manipulated by manipulating the\n`.expr` attribution to reinterpret the coin flips or manipulating\n`.valid` to condition on different coin flip outcomes.\n\nOut of the box `Distribution`s support a small number of operations:\n`+, <, <=, >=, >, ==, !=, ~, |, &, ^, .concat`, which they inherit\nfrom `aiger_bv.UnsignedBVExpr`. When using the same `.valid` predicate\n(same coin flips), these operations only manipulate the `.expr`\nattribute.\n\nMore generally, one can use the `apply` method to apply an arbitrary\nfunction to the `.expr` attribute. For example, using the dice from\nbefore:\n\n```python\ndice2 = dice.apply(lambda expr: ~expr[2])\nassert dice2[0].freqs() == Fraction(2, 3)\n```\n\nOne can also change the assumptions made on the coin flips by using\nthe condition method, for example, suppose we condition on the coin\nflips never being all `False`. This changes the distribution\nas follows:\n\n```python\ncoins = dice.coins  #  Bitvector Expression of coin variables.\ndice3 = dice.condition(coins != 0)\n\nprint(dice3.freqs())\n# [Fraction(0, 5), Fraction(3, 5), Fraction(2, 5)]\n```\n\n## Binomial Distributions\n\nAs a convenience, `py-aiger-coins` also supports encoding Binomial\ndistributions.\n\n```python\nx = binomial(3)\n\nprint(x.freqs())\n# (Fraction(1, 8), Fraction(3, 8), Fraction(3, 8), Fraction(1, 8))\n```\n\n## Markov Decision Processes and Probablistic Circuits\n\n`aiger_coins` also supports modeling Probablistic Circuits, Markov\nDecision Process (MDPs), and Markov Chains (MDPs with no inputs).\n\nInternally, the `MDP` object is simply an `AIGBV` bitvector circuit\nwith some inputs annotated with distributions over their inputs.\n\nThe primary entropy point to modeling a Markov Decision Process is\nthe `circ2mdp` function.\n\n```python\nfrom aiger_bv import atom\nfrom aiger_coins import circ2mdp\n\nx = atom(3, \'x\', signed=False)\ny = atom(3, \'y\', signed=False)\nexpr = (x & y).with_output(\'x&y\')\n\nmdp1 = circ2mdp(expr)\nmdp1 = circ2mdp(expr.aigbv)  # equivalent\n```\n\n### Composition\n\n`MDP` can be composed using an API analogous to `aiger_bv.AIGBV` and\n`aiger.AIG` sequential circuits. In addition, `MDP` support being feed\nactions from a distribution via sequential composition.\n\n```python\n# Put a distribution over the y input.\ndist = aiger_coins.dist((0, 1, 2), name=\'y\')\n\nmdp2 = dist >> mdp1\nmdp2 = mdp1 << dist  # equivalent\nmdp2 = circ2mdp(expr, {\'y\': dist})  # equivalent\n\nassert mdp1.inputs == {\'x\', \'y\'}\nassert mdp2.inputs == {\'x\'}\n\nmdp3 = mdp2 | circ2mdp(aiger_bv.identity_gate(4, \'z\'))\nassert mdp3.inputs == {\'x\', \'z\'}\nassert mdp3.outputs == {\'x&y\', \'z\'}\n\nmdp4 = mdp3.feedback(inputs=[\'z\'], outputs=[\'x&y\'], keep_outputs=True)\nassert mdp4.inputs == {\'x\'}\nassert mdp4.outputs == {\'x&y\', \'z\'}\n```\n\n### Extracting Circuit\nOne can transform an `MDP` into an `AIG` or `AIGBV` object using\n`.aig` and `.aigbv` attributes. This adds as the coinflips explicitly\nas inputs and also adds a special output `##valid` that monitors if\nthe sequence of inputs and coin flips was valid.\n\n```python\nassert mdp.aigbv.outputs == mdp.outputs | {\'##valid\'}\n\nassert \'##valid[0]\' in mdp.aig.outputs\n```\n\n\n### Encoding and Decoding Traces\n\nOften times, one is interested in analyzing traces, sequences of\nstates and actions, through a Markov Decision Process. \n\nIn order to map this to an execution of an `MDP` object, one needs to\nfind a sequence of coin flip inputs such that feeding the actions and\nthe coin flip inputs into the circuit generated by `MDP.aigbv`.\n\nThis (and its inverse) can be done via the `MDP.encode_trc` and\n`MDP.decode_trc` methods.\n\nFor example, consider the simple MDP modeled by:\n\n```python\nfrom aiger_bv import atom\nfrom aiger_coins import circ2mdp\n\naction = atom(1, \'action\', signed=False)\nx_prev = atom(1, \'x_prev\', signed=False)\nc = atom(1, \'c\', signed=False)\n\nx_next = (x_prev & c & action).with_output(\'x_next\')\n\nsys = circ2mdp(x_next).feedback(\n    keep_outputs=True,\n    inputs=[\'x_prev\'], outputs=[\'x_next\'], initials=[(True,)],\n)\nsys <<= coin((1, 2), name=\'c\')\nassert sys.inputs == {\'action\'}\nassert sys.outputs == {\'x_next\'}\n```\n\nWe can encode and decode traces into this model as follows:\n\n```\n# Encoding and Decoding\n\nsys_actions = 3*[{\'action\': (True,)}]\nstates = 3*[{out: (True,)}]\n\nactions = sys.encode_trc(sys_actions, states)\nassert not any(v[\'c\'][0] for v in actions)\n\nsys_actions2, states2 = sys.decode_trc(actions)\nassert sys_actions2 == sys_actions\nassert states2 == states\n```\n',
    'author': 'Marcell Vazquez-Chanlatte',
    'author_email': 'mvc@linux.com',
    'url': 'https://github.com/mvcisback/py-aiger-coins',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
