{"id":38518988,"url":"https://github.com/mvcisback/py-aiger","last_synced_at":"2026-01-17T06:36:38.112Z","repository":{"id":47589152,"uuid":"130783753","full_name":"mvcisback/py-aiger","owner":"mvcisback","description":"py-aiger: A python library for manipulating sequential and combinatorial circuits encoded using `and` \u0026 `inverter` gates (AIGs). ","archived":false,"fork":false,"pushed_at":"2025-12-21T02:02:19.000Z","size":615,"stargazers_count":49,"open_issues_count":2,"forks_count":9,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-12-22T23:07:15.703Z","etag":null,"topics":["aiger","circuit"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mvcisback.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-04-24T02:19:57.000Z","updated_at":"2025-12-21T02:02:23.000Z","dependencies_parsed_at":"2023-02-09T20:46:02.534Z","dependency_job_id":"594530e1-d850-4173-a6f2-9718d47355a0","html_url":"https://github.com/mvcisback/py-aiger","commit_stats":{"total_commits":484,"total_committers":7,"mean_commits":69.14285714285714,"dds":"0.17148760330578516","last_synced_commit":"19b3fe3837c3187dec08a5b58ba7cb36ca107c8d"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/mvcisback/py-aiger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvcisback%2Fpy-aiger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvcisback%2Fpy-aiger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvcisback%2Fpy-aiger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvcisback%2Fpy-aiger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mvcisback","download_url":"https://codeload.github.com/mvcisback/py-aiger/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvcisback%2Fpy-aiger/sbom","scorecard":{"id":669281,"data":{"date":"2025-08-11","repo":{"name":"github.com/mvcisback/py-aiger","commit":"af19a6e0e9922b39103f6f692c8aab449005ca26"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T19:22:54.622Z","repository_id":47589152,"created_at":"2025-08-21T19:22:54.623Z","updated_at":"2025-08-21T19:22:54.623Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28502612,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T04:31:57.058Z","status":"ssl_error","status_checked_at":"2026-01-17T04:31:45.816Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aiger","circuit"],"created_at":"2026-01-17T06:36:37.634Z","updated_at":"2026-01-17T06:36:38.105Z","avatar_url":"https://github.com/mvcisback.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cfigure\u003e\n  \u003cimg src=\"assets/logo_text.svg\" alt=\"py-aiger logo\" width=300px\u003e\n  \u003cfigcaption\u003e\n      pyAiger: A python library for manipulating sequential and\n      combinatorial circuits.\n  \u003c/figcaption\u003e\n\n\u003c/figure\u003e\n\n\n[![PyPI version](https://badge.fury.io/py/py-aiger.svg)](https://badge.fury.io/py/py-aiger)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1405781.svg)](https://doi.org/10.5281/zenodo.1405781)\n\n\u003c!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again --\u003e\n**Table of Contents**\n\n- [About PyAiger](#about-pyaiger)\n- [Installation](#installation)\n- [Development workflow](#development-workflow)\n- [Boolean Expression DSL](#boolean-expression-dsl)\n- [Sequential Circuit DSL](#sequential-circuit-dsl)\n    - [Sequential composition](#sequential-composition)\n    - [Parallel composition](#parallel-composition)\n    - [Circuits with Latches/Feedback/Delay](#circuits-with-latchesfeedbackdelay)\n    - [Relabeling](#relabeling)\n    - [Evaluation](#evaluation)\n    - [Useful circuits](#useful-circuits)\n- [Extra](#extra)\n- [Ecosystem](#ecosystem)\n- [Related Projects](#related-projects)\n- [Citing](#citing)\n\n\u003c!-- markdown-toc end --\u003e\n\n\n# About PyAiger\n\n1. Q: How is Py-Aiger pronounced? A: Like \"pie\" + \"grrr\".\n2. Q: Why python? Aren't you worried about performance?! A: No. The goals of this library are ease of use and hackability. \n3. Q: No, I'm really concerned about performance! A: This library is not suited to implement logic solvers. For everything else, such as the creation and manipulation of circuits with many thousands of gates in between solver calls, the library is really fast enough.\n4. Q: Where does the name come from? A: \u003ca href=\"http://fmv.jku.at/aiger/\"\u003eAiger\u003c/a\u003e is a popular circuit format. The format is used in \u003ca href=\"http://fmv.jku.at/hwmcc17/\"\u003ehardware model checking\u003c/a\u003e, \u003ca href=\"http://www.syntcomp.org/\"\u003esynthesis\u003c/a\u003e, and is supported by \u003ca href=\"https://github.com/berkeley-abc/abc\"\u003eABC\u003c/a\u003e. The name is a combination of AIG (standing for \u003ca href=\"https://en.wikipedia.org/wiki/And-inverter_graph\"\u003eAnd-Inverter-Graph\u003c/a\u003e) and the mountain \u003ca href=\"https://en.wikipedia.org/wiki/Eiger\"\u003eEiger\u003c/a\u003e.\n\n# Installation\n\nIf you just need to use `aiger`, you can just run:\n\n```\n$ pip install py-aiger\n```\n\nFor developers, see the [Development workflow](#development-workflow) section below.\n\n# Development workflow\n\nDevelopment uses `uv` for reproducible dependency and workspace management.\n\n```\n$ uv install\n```\n\nCommit the resulting `uv.lock` whenever dependencies change, and use\n`uv run \u003ccommand\u003e` for recurring tasks such as:\n\n```\n$ uv run pytest\n```\n\nIn a Nix shell give `uv` access to the locked environment via:\n\n```\nnix develop --command bash -c \"uv run pytest\"\n```\n\n### Updating the changelog\n\nCommitizen is bundled in the Nix dev shell so `cz bump` is available inside the locked environment. Run:\n\n```\n$ cz bump\n```\n\n# Usage\n\nCommands shown here assume you're executing Python through `uv run` (e.g., `uv run python` or via `nix develop --command bash -c \"uv run python\"`) so the locked dependencies are used.\n\n```\nimport aiger\n\nx, y, z, w = aiger.atoms('x', 'y', 'z', 'w')\n\nexpr1 = z.implies(x \u0026 y)\nexpr2 = z \u0026 w\n\ncirc1 = expr1.with_output('z') \\      # Get AIG for expr1 with output 'z'.\n             .aig\ncirc2 = circ1 \u003e\u003e circ2                # Feed outputs of circ1 into circ2.\n```\n\n# Boolean Expression DSL\nWhile powerful, when writing combinatorial circuits, the Sequential\nCircuit DSL can be somewhat clumsy. For this common usecase, we have\ndeveloped the Boolean Expression DSL. All circuits generated this way\nhave a single output.\n\n```python\nimport aiger\nx, y, z = aiger.atoms('x', 'y', 'z')\nexpr1 = x \u0026 y  # circuit with inputs 'x', 'y' and 1 output computing x AND y.\nexpr2 = x | y  # logical or.\nexpr3 = x ^ y  # logical xor.\nexpr4 = x == y  # logical ==, xnor.\nexpr5 = x.implies(y)\nexpr6 = ~x  # logical negation.\nexpr7 = aiger.ite(x, y, z)  # if x then y else z.\n\n# Atoms can be constants.\nexpr8 = x \u0026 True  # Equivalent to just x.\nexpr9 = x \u0026 False # Equivalent to const False.\n\n# Specifying output name of boolean expression.\n# - Output is a long uuid otherwise.\nexpr10 = expr5.with_output('x_implies_y')\nassert expr10.output == 'x_implies_y'\n\n# And you can inspect the AIG if needed.\ncirc = x.aig\n\n# And of course, you can get a BoolExpr from a single output aig.\nexpr10 = aiger.BoolExpr(circ)\n```\n\n\n# Sequential Circuit DSL\n\n```python\nimport aiger\nfrom aiger import utils\n\n# Parser for ascii AIGER format.\naig1 = aiger.load(path_to_aig1_file.aag)\naig2 = aiger.load(path_to_aig2_file.aag)\n```\n\n## Sequential composition\n```python\naig3 = aig1 \u003e\u003e aig2\n```\n\n## Parallel composition\n```python\naig4 = aig1 | aig2\n```\n\n## Circuits with Latches and Delayed Feedback\nSometimes one requires some outputs to be feed back into the circuits\nas time delayed inputs. This can be accomplished using the `loopback`\nmethod. This method takes in a variable number of dictionaries\nencoding how to wire an input to an output. The wiring dictionaries\nwith the following keys and default values:\n\n| Key         | Default | Meaning                          |\n| ----------- | ------- | -------------------------------- |\n| input       |         | Input port                       |\n| output      |         | Output port                      |\n| latch       | input   | Latch name                       |\n| init        | True    | Initial latch value              |\n| keep_output | True    | Keep loopbacked output as output |\n\n\n```python\n# Connect output y to input x with delay, initialized to True.\n# (Default initialization is False.)\naig5 = aig1.loopback({\n  \"input\": \"x\", \"output\": \"y\",\n})\n\naig6 = aig1.loopback({\n  \"input\": \"x\", \"output\": \"y\",\n}, {\n  \"input\": \"z\", \"output\": \"z\", \"latch\": \"z_latch\",\n  \"init\": False, \"keep_outputs\": False\n})\n\n```\n\n## Relabeling\n\nThere are two syntaxes for relabeling. The first uses indexing\nsyntax in a nod to [notation often used variable substition in math](https://mathoverflow.net/questions/243084/history-of-the-notation-for-substitution).\n\nThe syntax is the relabel method, which is preferable when one wants\nto be explicit, even for those not familar with `py-aiger`.\n\n```python\n# Relabel input 'x' to 'z'.\naig1['i', {'x': 'z'}]\naig1.relabel('input', {'x': 'z'})\n\n# Relabel output 'y' to 'w'.\naig1['o', {'y': 'w'}]\naig1.relabel('output', {'y': 'w'})\n\n# Relabel latches 'l1' to 'l2'.\naig1['l', {'l1': 'l2'}]\naig1.relabel('latch', {'l1': 'l2'})\n```\n\n## Evaluation\n```python\n# Combinatoric evaluation.\naig3(inputs={'x':True, 'y':False})\n\n# Sequential evaluation.\nsim = aig3.simulate([{'x': 0, 'y': 0}, \n                    {'x': 1, 'y': 2},\n                    {'x': 3, 'y': 4}])\n\n# Simulation Coroutine\nsim = aig3.simulator()  # Coroutine\nnext(sim)  # Initialize\nprint(sim.send({'x': 0, 'y': 0}))\nprint(sim.send({'x': 1, 'y': 2}))\nprint(sim.send({'x': 3, 'y': 4}))\n\n\n# Unroll\naig4 = aig3.unroll(steps=10, init=True)\n```\n\n## Useful circuits\n```python\n# Fix input x to be False.\naig4 = aiger.source({'x': False}) \u003e\u003e aig3\n\n# Remove output y. \naig4 = aig3 \u003e\u003e aiger.sink(['y'])\n\n# Create duplicate w of output y.\naig4 = aig3 \u003e\u003e aiger.tee({'y': ['y', 'w']})\n```\n\n# Extra\n```python\naiger.common.eval_order(aig1)  # Returns topological ordering of circuit gates.\n\n# Convert object into an AIG from multiple formats including BoolExpr, AIG, str, and filepaths.\naiger.to_aig(aig1)\n```\n\n# Ecosystem\n\n### Stable\n- [py-aiger-bv](https://github.com/mvcisback/py-aiger-bv): Extension of pyAiger for manipulating sequential bitvector circuits.\n- [py-aiger-cnf](https://github.com/mvcisback/py-aiger-cnf): BoolExpr to Object representing CNF. Mostly used for interfacing with py-aiger-sat.\n- [py-aiger-past-ltl](https://github.com/mvcisback/py-aiger-past-ltl): Converts Past Linear Temporal Logic to aiger circuits.\n- [py-aiger-coins](https://github.com/mvcisback/py-aiger-coins): Library for creating circuits that encode discrete distributions.\n- [py-aiger-sat](https://github.com/mvcisback/py-aiger-sat): Bridge between py-aiger and py-sat.\n- [py-aiger-bdd](https://github.com/mvcisback/py-aiger-bdd): Aiger \u003c-\u003e BDD bridge.\n- [py-aiger-gridworld](https://github.com/mvcisback/py-aiger-gridworld): Create aiger circuits representing gridworlds.\n- [py-aiger-dfa](https://pypi.org/project/py-aiger-dfa/): Convert between finite automata and sequential circuits.\n\n\n### Underdevelopment\n\n\n- [py-aiger-spectral](https://github.com/mvcisback/py-aiger-spectral): A tool for performing (Fourier) Analysis of Boolean Functions.\n- [py-aiger-abc](https://pypi.org/project/py-aiger-abc/): Aiger and abc bridge.\n\n# Related Projects\n- [pyAig](https://github.com/sterin/pyaig): Another python library\n  for working with AIGER circuits.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvcisback%2Fpy-aiger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmvcisback%2Fpy-aiger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvcisback%2Fpy-aiger/lists"}