py-aiger-bv


Namepy-aiger-bv JSON
Version 4.7.7 PyPI version JSON
download
home_page
SummaryA python library for manipulating sequential and-inverter gates.
upload_time2024-03-16 19:57:46
maintainer
docs_urlNone
authorMarcell Vazquez-Chanlatte
requires_python>=3.7,<4.0
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <figure>
  <img src="logo_text.svg" alt="py-aiger-bv logo" width=300px>
  <figcaption>pyAiger-BV: Extension of pyAiger for manipulating
    sequential bitvector circuits.</figcaption>
</figure>


[![Build Status](https://cloud.drone.io/api/badges/mvcisback/py-aiger-bv/status.svg)](https://cloud.drone.io/mvcisback/py-aiger-bv)
[![Docs](https://img.shields.io/badge/API-link-color)](https://mvcisback.github.io/py-aiger-bv)
[![PyPI version](https://badge.fury.io/py/py-aiger-bv.svg)](https://badge.fury.io/py/py-aiger-bv)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
 
# Table of Contents
- [About](#about-py-aiger-bv)
- [Installation](#installation)
- [BitVector Expr DSL](#bitvector-expression-dsl)
- [Sequential Circuit DSL](#sequential-circuit-dsl)

# About Py-Aiger-BV

This library provides word level abstractions on top of
[py-aiger](https://github.com/mvcisback/py-aiger). This is done by the
`AIGBV` which groups inputs, outputs, and latches into named
**ordered** sequences, e.g. bitvectors.

The resulting objects can be turned into `AIG`s where each input,
output, or latches name has its index appended to its name. For example,
an bitvector input, `'x'` with 3 bits becomes inputs `'x[0]', 'x[1]', 'x[3]'`


# Installation

If you just need to use `aiger_bv`, you can just run:

`$ pip install py-aiger-bv`

For developers, note that this project uses the
[poetry](https://poetry.eustace.io/) python package/dependency
management tool. Please familarize yourself with it and then
run:

`$ poetry install`

# BitVector Expression DSL

As in py-aiger, when writing combinatorial circuits, the Sequential
Circuit DSL can be somewhat clumsy. For this common usecase, we have
developed the BitVector Expression DSL. This DSL actually consists of
two DSLs for signed and unsigned BitVectors.  All circuits generated
this way have a single output word. We use a **big-endian** encoding
where the most significant digit is the first element of the tuple
representing the word. For signed numbers, two's complement is used.

```python
import aiger_bv

# Create 16 bit variables.
x = aiger_bv.atom(16, 'x')
y = aiger_bv.atom(16, 'y', signed=True)  # Signed by default.
z = aiger_bv.uatom(16, 'z')              # Equiv to signed=False.

# bitwise ops.
expr1 = x & y  # Bitwise and.
expr2 = x | y  # Bitwise or.
expr3 = x ^ y  # Bitwise xor.
expr4 = ~x  # Bitwise negation.

# arithmetic
expr5 = x + y
expr6 = x - y
expr7 = x << y
expr8 = x >> y  # logical if unsigned, arithmetic if signed.
expr9 = -x  # Arithmetic negation. Only defined for signed expr.
expr10 = abs(x)
expr11 = x @ y  # inner product of bitvectors mod 2 (+ is xor).

# comparison
expr12 = x == y
expr13 = x != y
expr14 = x < y
expr15 = x <= y
expr16 = x > y
expr17 = x >= y

# Atoms can be constants.
expr18 = x & aiger_bv.atom(16, 3)
expr19 = x & aiger_bv.atom(16, 0xff)

# BitVector expressions can be concatenated.
expr20 = x.concat(y)

# Particular bits can be indexed to create new expressions.
expr21 = x[1]

# Single bit expressions can be repeated.
expr22 = x[1].repeat(10)

# And you can inspect the AIGBV if needed.
circ = x.aigbv

# And you can inspect the AIG if needed.
circ = x.aigbv.aig

# And of course, you can get a BoolExpr from a single output aig.
expr = aiger_bv.UnsignedBVExpr(circ)
```

# Sequential Circuit DSL

py-aiger-bv's Sequential Circuit DSL implements the same basic api as
py-aiger's Sequential Circuit DSL, but operates at the (variable
length) word level rather than the bit level.

```python
import aiger
import aiger_bv


circ = ... # Create a circuit (see below).

# We assume this circuit has word level
# inputs: x,y, outputs: z, w, q, latches: a, b
assert circ.inputs == {'x', 'y'}
assert circ.outputs == {'z', 'w', 'q'}
assert circ.latches == {'a', 'b'}
```

## Sequential composition
```python
circ3 = circ1 >> circ2
```

## Parallel composition
```python
circ3 = circ1 | circ2
```

## Adding Feedback (inserts a delay)
```python
# Connect output y to input x with delay (initialized to True).
# (Default initialization is False.)
cir2 = circ.feedback(
    inputs=['x'],
    outputs=['y'],
    initials=[True],
    keep_outputs=True
)
```

## Relabeling
```python
# Relabel input 'x' to 'z'.
circ2 = circ['i', {'x': 'z'}]

# Relabel output 'y' to 'w'.
circ2 = circ['o', {'y': 'w'}]

# Relabel latches 'l1' to 'l2'.
circ2 = circ['l', {'l1': 'l2'}]
```

## Evaluation
```python
# Combinatoric evaluation.
circ(inputs={'x':(True, False, True), 'y': (True, False)})

# Sequential evaluation.
circ.simulate([
        {'x': (True, False, True), 'y': (True, False)},
        {'x': (False, False, True), 'y': (False, False)},
    ])

# Simulation Coroutine.
sim = circ.simulator()  # Coroutine
next(sim)  # Initialize
print(sim.send({'x': (True, False, True), 'y': (True, False)}))
print(sim.send({'x': (False, False, True), 'y': (False, False)}))


# Unroll
circ2 = circ.unroll(steps=10, init=True)
```

## aiger.AIG to aiger.AIGBV

There are two main ways to take an object `AIG` from `aiger` and
convert it into an `AIGBV` object. The first is the `aig2aigbv`
command which simply makes all inputs words of size 1.


```python
# Create aiger_bv.AIGERBV object from aiger.AIG object.
circ  = ... # Some aiger.AIG object
word_circ = aiger_bv.aig2aigbv(circ)  # aiger_bv.AIGBV object


```

## Gadget Library

### General Manipulation

```python
# Copy outputs 'x' and 'y' to 'w1, w2' and 'z1, z2'.
circ1 = circ >> aiger_bv.tee(wordlen=3, iomap={
        'x': ('w1', 'w2'),
        'y': ('z1', 'z2')
    })

# Take 1 bit output, 'x', duplicate it 5 times, and group into
# a single 5-length word output, 'y'.
circ2 = circ >> aiger_bv.repeat(wordlen=5, input='x', output='z')

# Reverse order of a word.
circ3 = circ >> aiger_bv.reverse_gate(wordlen=5, input='x', output='z')

# Sink and Source circuits (see encoding section for encoding details).
## Always output binary encoding for 15. 
circ4 = aiger_bv.source(wordlen=4, value=15, name='x', signed=False)

## Absorb output 'y'
circ5 = circ >> aiger_bv.sink(wordlen=4, inputs=['y'])

# Identity Gate
circ6 = circ >> aiger_bv.identity_gate(wordlen=3, input='x')

# Combine/Concatenate words
circ7 = circ >> aiger_bv.combine_gate(
    left_wordlen=3, left='x',
    right_wordlen=3, right='y',
    output='z'
)

# Split words
circ8 = circ >> aiger_bv.split_gate(
    input='x',
    left_wordlen=1, left='z',
    right_wordlen=2, right='w'
)

# Select single index of circuit and make it a wordlen=1 output.
circ9 = circ >> aiger_bv.index_gate(wordlen=3, idx=1, input='x', output='x1')
```

## Bitwise Operations

- `aiger_bv.bitwise_and(3, left='x', right='y', output='x&y')`
- `aiger_bv.bitwise_or(3, left='x', right='y', output='x|y')`
- `aiger_bv.bitwise_xor(3, left='x', right='y', output='x^y')`
- `aiger_bv.bitwise_negate(3, left='x', output='~x')`

## Arithmetic

- `aiger_bv.add_gate(3, left='x', right='y', output='x+y')`
- `aiger_bv.subtract_gate_gate(3, left='x', right='y', output='x-y')`
- `aiger_bv.inc_gate(3, left='x', output='x+1')`
- `aiger_bv.dec_gate(3, left='x', output='x+1')`
- `aiger_bv.negate_gate(3, left='x', output='-x')`
- `aiger_bv.logical_right_shift(3, shift=1, input='x', output='x>>1')`
- `aiger_bv.arithmetic_right_shift(3, shift=1, input='x', output='x>>1')`
- `aiger_bv.left_shift(3, shift=1, input='x', output='x<<1')`

## Comparison

- `aiger_bv.is_nonzero_gate(3, input='x', output='is_nonzero')`
- `aiger_bv.is_zero_gate(3, input='x', output='is_zero')`
- `aiger_bv.eq_gate(3, left='x', right='y', output='x=y')`
- `aiger_bv.ne_gate(3, left='x', right='y', output='x!=y')`
- `aiger_bv.unsigned_lt_gate(3, left='x', right='y', output='x<y')`
- `aiger_bv.unsigned_gt_gate(3, left='x', right='y', output='x>y')`
- `aiger_bv.unsigned_le_gate(3, left='x', right='y', output='x<=y')`
- `aiger_bv.unsigned_ge_gate(3, left='x', right='y', output='x>=y')`
- `aiger_bv.signed_lt_gate(3, left='x', right='y', output='x<y')`
- `aiger_bv.signed_gt_gate(3, left='x', right='y', output='x>y')`
- `aiger_bv.signed_le_gate(3, left='x', right='y', output='x<=y')`
- `aiger_bv.signed_ge_gate(3, left='x', right='y', output='x>=y')`

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "py-aiger-bv",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Marcell Vazquez-Chanlatte",
    "author_email": "mvc@linux.com",
    "download_url": "https://files.pythonhosted.org/packages/c5/01/103c9f1e93e745a6bbb9570f752a6ac3f90d374a4ecdc65847d49437ae9a/py_aiger_bv-4.7.7.tar.gz",
    "platform": null,
    "description": "<figure>\n  <img src=\"logo_text.svg\" alt=\"py-aiger-bv logo\" width=300px>\n  <figcaption>pyAiger-BV: Extension of pyAiger for manipulating\n    sequential bitvector circuits.</figcaption>\n</figure>\n\n\n[![Build Status](https://cloud.drone.io/api/badges/mvcisback/py-aiger-bv/status.svg)](https://cloud.drone.io/mvcisback/py-aiger-bv)\n[![Docs](https://img.shields.io/badge/API-link-color)](https://mvcisback.github.io/py-aiger-bv)\n[![PyPI version](https://badge.fury.io/py/py-aiger-bv.svg)](https://badge.fury.io/py/py-aiger-bv)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n \n# Table of Contents\n- [About](#about-py-aiger-bv)\n- [Installation](#installation)\n- [BitVector Expr DSL](#bitvector-expression-dsl)\n- [Sequential Circuit DSL](#sequential-circuit-dsl)\n\n# About Py-Aiger-BV\n\nThis library provides word level abstractions on top of\n[py-aiger](https://github.com/mvcisback/py-aiger). This is done by the\n`AIGBV` which groups inputs, outputs, and latches into named\n**ordered** sequences, e.g. bitvectors.\n\nThe resulting objects can be turned into `AIG`s where each input,\noutput, or latches name has its index appended to its name. For example,\nan bitvector input, `'x'` with 3 bits becomes inputs `'x[0]', 'x[1]', 'x[3]'`\n\n\n# Installation\n\nIf you just need to use `aiger_bv`, you can just run:\n\n`$ pip install py-aiger-bv`\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\nrun:\n\n`$ poetry install`\n\n# BitVector Expression DSL\n\nAs in py-aiger, when writing combinatorial circuits, the Sequential\nCircuit DSL can be somewhat clumsy. For this common usecase, we have\ndeveloped the BitVector Expression DSL. This DSL actually consists of\ntwo DSLs for signed and unsigned BitVectors.  All circuits generated\nthis way have a single output word. We use a **big-endian** encoding\nwhere the most significant digit is the first element of the tuple\nrepresenting the word. For signed numbers, two's complement is used.\n\n```python\nimport aiger_bv\n\n# Create 16 bit variables.\nx = aiger_bv.atom(16, 'x')\ny = aiger_bv.atom(16, 'y', signed=True)  # Signed by default.\nz = aiger_bv.uatom(16, 'z')              # Equiv to signed=False.\n\n# bitwise ops.\nexpr1 = x & y  # Bitwise and.\nexpr2 = x | y  # Bitwise or.\nexpr3 = x ^ y  # Bitwise xor.\nexpr4 = ~x  # Bitwise negation.\n\n# arithmetic\nexpr5 = x + y\nexpr6 = x - y\nexpr7 = x << y\nexpr8 = x >> y  # logical if unsigned, arithmetic if signed.\nexpr9 = -x  # Arithmetic negation. Only defined for signed expr.\nexpr10 = abs(x)\nexpr11 = x @ y  # inner product of bitvectors mod 2 (+ is xor).\n\n# comparison\nexpr12 = x == y\nexpr13 = x != y\nexpr14 = x < y\nexpr15 = x <= y\nexpr16 = x > y\nexpr17 = x >= y\n\n# Atoms can be constants.\nexpr18 = x & aiger_bv.atom(16, 3)\nexpr19 = x & aiger_bv.atom(16, 0xff)\n\n# BitVector expressions can be concatenated.\nexpr20 = x.concat(y)\n\n# Particular bits can be indexed to create new expressions.\nexpr21 = x[1]\n\n# Single bit expressions can be repeated.\nexpr22 = x[1].repeat(10)\n\n# And you can inspect the AIGBV if needed.\ncirc = x.aigbv\n\n# And you can inspect the AIG if needed.\ncirc = x.aigbv.aig\n\n# And of course, you can get a BoolExpr from a single output aig.\nexpr = aiger_bv.UnsignedBVExpr(circ)\n```\n\n# Sequential Circuit DSL\n\npy-aiger-bv's Sequential Circuit DSL implements the same basic api as\npy-aiger's Sequential Circuit DSL, but operates at the (variable\nlength) word level rather than the bit level.\n\n```python\nimport aiger\nimport aiger_bv\n\n\ncirc = ... # Create a circuit (see below).\n\n# We assume this circuit has word level\n# inputs: x,y, outputs: z, w, q, latches: a, b\nassert circ.inputs == {'x', 'y'}\nassert circ.outputs == {'z', 'w', 'q'}\nassert circ.latches == {'a', 'b'}\n```\n\n## Sequential composition\n```python\ncirc3 = circ1 >> circ2\n```\n\n## Parallel composition\n```python\ncirc3 = circ1 | circ2\n```\n\n## Adding Feedback (inserts a delay)\n```python\n# Connect output y to input x with delay (initialized to True).\n# (Default initialization is False.)\ncir2 = circ.feedback(\n    inputs=['x'],\n    outputs=['y'],\n    initials=[True],\n    keep_outputs=True\n)\n```\n\n## Relabeling\n```python\n# Relabel input 'x' to 'z'.\ncirc2 = circ['i', {'x': 'z'}]\n\n# Relabel output 'y' to 'w'.\ncirc2 = circ['o', {'y': 'w'}]\n\n# Relabel latches 'l1' to 'l2'.\ncirc2 = circ['l', {'l1': 'l2'}]\n```\n\n## Evaluation\n```python\n# Combinatoric evaluation.\ncirc(inputs={'x':(True, False, True), 'y': (True, False)})\n\n# Sequential evaluation.\ncirc.simulate([\n        {'x': (True, False, True), 'y': (True, False)},\n        {'x': (False, False, True), 'y': (False, False)},\n    ])\n\n# Simulation Coroutine.\nsim = circ.simulator()  # Coroutine\nnext(sim)  # Initialize\nprint(sim.send({'x': (True, False, True), 'y': (True, False)}))\nprint(sim.send({'x': (False, False, True), 'y': (False, False)}))\n\n\n# Unroll\ncirc2 = circ.unroll(steps=10, init=True)\n```\n\n## aiger.AIG to aiger.AIGBV\n\nThere are two main ways to take an object `AIG` from `aiger` and\nconvert it into an `AIGBV` object. The first is the `aig2aigbv`\ncommand which simply makes all inputs words of size 1.\n\n\n```python\n# Create aiger_bv.AIGERBV object from aiger.AIG object.\ncirc  = ... # Some aiger.AIG object\nword_circ = aiger_bv.aig2aigbv(circ)  # aiger_bv.AIGBV object\n\n\n```\n\n## Gadget Library\n\n### General Manipulation\n\n```python\n# Copy outputs 'x' and 'y' to 'w1, w2' and 'z1, z2'.\ncirc1 = circ >> aiger_bv.tee(wordlen=3, iomap={\n        'x': ('w1', 'w2'),\n        'y': ('z1', 'z2')\n    })\n\n# Take 1 bit output, 'x', duplicate it 5 times, and group into\n# a single 5-length word output, 'y'.\ncirc2 = circ >> aiger_bv.repeat(wordlen=5, input='x', output='z')\n\n# Reverse order of a word.\ncirc3 = circ >> aiger_bv.reverse_gate(wordlen=5, input='x', output='z')\n\n# Sink and Source circuits (see encoding section for encoding details).\n## Always output binary encoding for 15. \ncirc4 = aiger_bv.source(wordlen=4, value=15, name='x', signed=False)\n\n## Absorb output 'y'\ncirc5 = circ >> aiger_bv.sink(wordlen=4, inputs=['y'])\n\n# Identity Gate\ncirc6 = circ >> aiger_bv.identity_gate(wordlen=3, input='x')\n\n# Combine/Concatenate words\ncirc7 = circ >> aiger_bv.combine_gate(\n    left_wordlen=3, left='x',\n    right_wordlen=3, right='y',\n    output='z'\n)\n\n# Split words\ncirc8 = circ >> aiger_bv.split_gate(\n    input='x',\n    left_wordlen=1, left='z',\n    right_wordlen=2, right='w'\n)\n\n# Select single index of circuit and make it a wordlen=1 output.\ncirc9 = circ >> aiger_bv.index_gate(wordlen=3, idx=1, input='x', output='x1')\n```\n\n## Bitwise Operations\n\n- `aiger_bv.bitwise_and(3, left='x', right='y', output='x&y')`\n- `aiger_bv.bitwise_or(3, left='x', right='y', output='x|y')`\n- `aiger_bv.bitwise_xor(3, left='x', right='y', output='x^y')`\n- `aiger_bv.bitwise_negate(3, left='x', output='~x')`\n\n## Arithmetic\n\n- `aiger_bv.add_gate(3, left='x', right='y', output='x+y')`\n- `aiger_bv.subtract_gate_gate(3, left='x', right='y', output='x-y')`\n- `aiger_bv.inc_gate(3, left='x', output='x+1')`\n- `aiger_bv.dec_gate(3, left='x', output='x+1')`\n- `aiger_bv.negate_gate(3, left='x', output='-x')`\n- `aiger_bv.logical_right_shift(3, shift=1, input='x', output='x>>1')`\n- `aiger_bv.arithmetic_right_shift(3, shift=1, input='x', output='x>>1')`\n- `aiger_bv.left_shift(3, shift=1, input='x', output='x<<1')`\n\n## Comparison\n\n- `aiger_bv.is_nonzero_gate(3, input='x', output='is_nonzero')`\n- `aiger_bv.is_zero_gate(3, input='x', output='is_zero')`\n- `aiger_bv.eq_gate(3, left='x', right='y', output='x=y')`\n- `aiger_bv.ne_gate(3, left='x', right='y', output='x!=y')`\n- `aiger_bv.unsigned_lt_gate(3, left='x', right='y', output='x<y')`\n- `aiger_bv.unsigned_gt_gate(3, left='x', right='y', output='x>y')`\n- `aiger_bv.unsigned_le_gate(3, left='x', right='y', output='x<=y')`\n- `aiger_bv.unsigned_ge_gate(3, left='x', right='y', output='x>=y')`\n- `aiger_bv.signed_lt_gate(3, left='x', right='y', output='x<y')`\n- `aiger_bv.signed_gt_gate(3, left='x', right='y', output='x>y')`\n- `aiger_bv.signed_le_gate(3, left='x', right='y', output='x<=y')`\n- `aiger_bv.signed_ge_gate(3, left='x', right='y', output='x>=y')`\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A python library for manipulating sequential and-inverter gates.",
    "version": "4.7.7",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e3684de78cadc87956741fe92b84f83f8642104243ef249b61bb3afd0579ecb0",
                "md5": "ba5ab1450dac19e79cccb0eacb011a38",
                "sha256": "4e06bf68f0614c2c1db1f675923754c0e2a917182cde74fa2f47b0a08ed1a31c"
            },
            "downloads": -1,
            "filename": "py_aiger_bv-4.7.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ba5ab1450dac19e79cccb0eacb011a38",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 15483,
            "upload_time": "2024-03-16T19:57:44",
            "upload_time_iso_8601": "2024-03-16T19:57:44.851461Z",
            "url": "https://files.pythonhosted.org/packages/e3/68/4de78cadc87956741fe92b84f83f8642104243ef249b61bb3afd0579ecb0/py_aiger_bv-4.7.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c501103c9f1e93e745a6bbb9570f752a6ac3f90d374a4ecdc65847d49437ae9a",
                "md5": "6cd9857a34fbed488451a467ca9e9a26",
                "sha256": "b78e1f3cc97b5e0b492bf7828d690f1a124f09f97ad9487b2842c848a205c274"
            },
            "downloads": -1,
            "filename": "py_aiger_bv-4.7.7.tar.gz",
            "has_sig": false,
            "md5_digest": "6cd9857a34fbed488451a467ca9e9a26",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 16304,
            "upload_time": "2024-03-16T19:57:46",
            "upload_time_iso_8601": "2024-03-16T19:57:46.772902Z",
            "url": "https://files.pythonhosted.org/packages/c5/01/103c9f1e93e745a6bbb9570f752a6ac3f90d374a4ecdc65847d49437ae9a/py_aiger_bv-4.7.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-16 19:57:46",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "py-aiger-bv"
}
        
Elapsed time: 0.19614s