{"id":14977312,"url":"https://github.com/the-pinbo/robdd","last_synced_at":"2025-03-02T04:28:30.946Z","repository":{"id":67029135,"uuid":"539817854","full_name":"the-pinbo/ROBDD","owner":"the-pinbo","description":"A binary decision diagram is a directed acyclic graph used to represent a Boolean function. The ROBDD is a canonical form, which means that given an identical ordering of input variables, equivalent Boolean functions will always reduce to the same ROBDD. ","archived":false,"fork":false,"pushed_at":"2022-10-02T13:41:36.000Z","size":5657,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-12T17:09:37.270Z","etag":null,"topics":["bdd","bdds","boolean-algebra","graphviz-dot","ipynb-jupyter-notebook","pthon3","robdd","vlsi","vlsi-cad"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/the-pinbo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-22T05:44:02.000Z","updated_at":"2025-01-06T16:24:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"7459b688-b9c5-4753-81c8-01b26cd6d417","html_url":"https://github.com/the-pinbo/ROBDD","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-pinbo%2FROBDD","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-pinbo%2FROBDD/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-pinbo%2FROBDD/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-pinbo%2FROBDD/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/the-pinbo","download_url":"https://codeload.github.com/the-pinbo/ROBDD/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241460008,"owners_count":19966511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["bdd","bdds","boolean-algebra","graphviz-dot","ipynb-jupyter-notebook","pthon3","robdd","vlsi","vlsi-cad"],"created_at":"2024-09-24T13:55:26.688Z","updated_at":"2025-03-02T04:28:25.935Z","avatar_url":"https://github.com/the-pinbo.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Implementation of ROBDD\n\n\u003e Implementation of ROBDD using python3 visualizing it using graphviz and pydot\n\u003e\n\u003e ## Submitted by :\n\u003e\n\u003e ### 1. Inbasekaran P (201EC226)\n\u003e\n\u003e ### 2. Pranav Koundinya (201EC247)\n\u003e\n\u003e ### 3. Trivendra Tiwari 201EC163)\n\n## Introduction:\n\nBinary Decision Diagrams(BDDs) are an effective data structure to represent boolean functions. BDDs are referred to as Directed Acyclic Graphs(DAGs). BDDs, however, are not canonical forms of describing boolean functions. But a certain kind of BDDs, called the Reduced Ordered BDDs(ROBDDs) are canonical for that particular ordering. ROBDDs are BDDs following a specified variable ordering and simplified/reduced using reduction rules. This is a very desirable property for determining formal equivalence.\n\nTwo reduction rules exist for converting an OBDD into a ROBDD:\n\n1. Merge equivalent leaves\n\n```python\n\n# Reduction rule 1\n# is lo is hi then return lo\n\nif nodeLo is nodeHi:\n    exp = nodeLo.exp\n    node = nodeLo\n\n```\n\n2. Merge isomorphic nodes\n\n```python\n\n# Reduction rule 2\n# if the node is already present in the cache then return the node\n\nkey = (var, id(nodeLo), id(nodeHi))\n\ntry:\n    node = cache[key]\nexcept  KeyError:\n    node = Node(var, nodeLo, nodeHi)\n    cache[key] = node\n```\n\n\u003e Example: The BDD for the Boolean function\n\u003e $$f(X_1,X_2,X_3)= X_1 . \\bar X_2 . \\bar X_3+ X_1.X_2 + X_2.X_3$$\n\n\u003e ![bdd image](https://upload.wikimedia.org/wikipedia/commons/9/91/BDD.png)\n\nThe ROBDD for the same function with the variable ordering $X_1 \\lt X_2 \\lt X_3$, is shown below:\n\n![bdd image](https://upload.wikimedia.org/wikipedia/commons/1/14/BDD_simple.svg)\n\n### How does variable ordering affect the BDD?\n\nROBDD of $f(X_1,X_2,X_3,X_4,X_5,X_6,X_7,X_8) = X_1.X_2 + X_3.X_4 + X_5.X_6 + X_7.X_8$\n\nOrdering : $X_1\\lt X_2 \\lt X_3 \\lt X_4 \\lt X_5 \\lt X_6 \\lt X_7 \\lt X_8$\n\n![ex1](https://upload.wikimedia.org/wikipedia/commons/4/4b/BDD_Variable_Ordering_Good.svg)\n\nordering : $X_1 \\lt X_3 \\lt X_5 \\lt X_7 \\lt X_2 \\lt X_4 \\lt X_6 \\lt X_8$\n\n![ex2](https://upload.wikimedia.org/wikipedia/commons/2/28/BDD_Variable_Ordering_Bad.svg)\n\nEven though the above graphs are ROBDDs of the same Boolean function, the former is the result of a bad variable ordering, while the latter is the result of optimal ordering. This indicates that just reducing the BDD to ROBDD does not give an optimal representation, but starting with a good variable ordering does. For a small number of variables, one can try various combinations of variable ordering and select the optimal ordering. This, however, is not feasible when the boolean function contains a large number of variables, say 100. One can use heuristic approaches such as Minato’s Heuristic to come up with a variable ordering which is ‘good enough, if not optimal.\n\n## Input File Format\n\n### PCN File Format\n\nWe are using a very simple text file format for this program. Our code will read a Boolean function specified in this format. The file format looks like this:\n\n- The _first line_ of the file is a single positive `int` n: the number of variables. We number the variables starting with index 1, so if number was 3, the variables in your problem are $X_1, X_2, X_3$\n\n- The second line of the file is a single positive `int` m: number of cubes in this cube list. If there are 10 cubes in this file, this is a “10”.\n\n- Each of the subsequent m lines of the file describes one cube : you have the same number of lines as the second line of your file. The first number on the line says how many variables are not don't cares in this cube. If this number is, e.g., 5, then the next 5 numbers on the line specify the true or complemented form of each variable in this cube. We use a simple convention: if variable $x_k$ appears in true form, then put integer $“k”$ on the line; if variable $x_k$ appears in complement form $\\bar x_k$ then put integer $“-k”$ on the line\n\n_Example :_\n\nSuppose we have a function\n$$f = X_1.X_2 + X_2.X_3 + X_3.X_1$$\n\n```\n3\n3\n2 1 2\n2 2 3\n2 1 3\n\n```\n\n## Implementation\n\nBDD if-then-else **(ITE)** operator. The ITE operator is the most important operation in BDDs. It is used to construct BDDs from other BDDs.\nThe _f_, _g_, and _h_ arguments are BDDs.\nThe ITE(f, g, h) operator means\nif _f_ is true, return _g_, else return _h_\".It is equivalent to:\n\n- DNF form: `f \u0026 g | ~f \u0026 h`\n- CNF form: `(~f | g) \u0026 (f | h)`\n  The ITE operator is defined as follows:\n\n```python\n\"\"\"Return node that results from recursively applying ITE(f, g, h).\"\"\"\n    # ITE(f, 1, 0) = f\n    if g is BDDNODEONE and h is BDDNODEZERO:\n        return f\n    # ITE(f, 0, 1) = f'\n    elif g is BDDNODEZERO and h is BDDNODEONE:\n        return _neg(f)\n    # ITE(1, g, h) = g\n    elif f is BDDNODEONE:\n        return g\n    # ITE(0, g, h) = h\n    elif f is BDDNODEZERO:\n        return h\n    # ITE(f, g, g) = g\n    elif g is h:\n        return g\n    else:\n        # ITE(f, g, h) = ITE(x, ITE(fx, gx, hx), ITE(fx', gx', hx'))\n        # where x is the variable of f with the lowest index\n        return bddnode(root, ite(fv1, gv1, hv1), ite(fv0, gv0, hv0))\n```\n\nWe build the bdd nodes using the shannon's expansion theorem in a bottom up post order manner to avoid recomputation and to reduce the number of nodes in the bdd. The bdd is built using the following steps:\n\n```python\n# build the bdd\n        self.node = self.buildBDD()\n```\n\n```python\ndef buildBDD(exp, ordering, cache):\n    \"\"\" builds the bdd \"\"\"\n    # if expression is false return the zero node\n    if exp.isFalse():\n        return cache[BDDNode.BDDNODEZEROKEY]\n    # if expression is true return the one node\n    if exp.isTrue():\n        return cache[BDDNode.BDDNODEONEKEY]\n    # get the variable with the highest priority\n    for idx, var in enumerate(ordering):\n        if exp.isPresent(var):\n            # build the node for the variable\n            return bddNode(exp, ordering, cache, idx)\n    # if no variable is present throw an error\n    raise ValueError(\"invalid ordering list\")\n\n```\n\n```python\ndef bddNode(exp, ordering, cache, idx):\n    \"\"\" returns the bdd node \"\"\"\n    # get the variable\n    var = ordering[idx]\n    # build the lo node\n    nodeLo = buildBDD(exp.negativeCofactor(var), ordering, cache)\n    # build the hi node\n    nodeHi = buildBDD(exp.positiveCofactor(var), ordering, cache)\n    # Reduction rule 1\n    # is lo is hi then return lo\n    if nodeLo is nodeHi:\n        exp = nodeLo.exp\n        node = nodeLo\n    else:\n        # Reduction rule 2\n        # if the node is already present in the cache then return the node\n        key = (var, id(nodeLo), id(nodeHi))\n        try:\n            node = cache[key]\n        except KeyError:\n            # create the node if no reduction is possible\n            node = BDDNode(exp, var)\n            node.lo = nodeLo\n            node.hi = nodeHi\n            # store it in the cache\n            cache[key] = node\n    return node\n```\n\n## Setup\n\n`https://github.com/the-pinbo/ROBDD`\nSimply clone this git hub repo and run `example.ipynb ` with appropriate pcn files an input form the `./input` directory , further instructions and examples are given there, also make sure to install the dependencies.\n\n\u003e To install the dependencies type the following in the terminal\n\u003e\n\u003e `$ pip install -r requirements.txt`\n\n## Example 1\n\n### Steps\n\n#### **Step 1**\n\nimport myBdd module\n\n```py\nfrom myBdd import *\n```\n\n#### **Step 2**\n\nRead the .pcn file and create an instance of `Expression()`\n\nBoolean Function:\n$$f(X_1, X_2, X_3) = X_1.X_2.X_3 +\\overline{X_3}.X_4 + \\overline{X_2}.X_4$$\n\n```py\nf = boolfunc.Expression(r\"input\\1.pcn\")\nprint(f)\n```\n\n\u003e Output:\n\n```\n    4\n    3\n    3 1 2 3\n    2 -2 4\n    2 -3 4\n```\n\n#### **Step 3**\n\nInput the ordering of the variabes as a list and create an instance of `BDD()`\n\n```py\nordering = [2,3,4,1]\nprint(ordering)\na = BDD(f, ordering)\na\n\n```\n\n\u003e Output:\n\n```output\n[2, 3, 4, 1]\n```\n\n#### **Step 4**\n\nDisplay the DAG using the `.displayGraph()` method\n\n```py\na.displayGraph()\n```\n\n![](./img/76ad986ba190202e53fe3f97f6db2e684074c3f5.png)\n\nThe following cells display the BDDs for variable orderings of the Boolean function\n$$X_1 \\lt X_2 \\lt X_3 \\lt X_4$$\n\n```python\nordering = [1,2,3,4]\nprint(ordering)\na = BDD(f, ordering)\na.displayGraph()\n```\n\n\u003e Output:\n\n```\n[1, 2, 3, 4]\n```\n\n![](./img/64d48c6de6c6a2fbe9d2beffbc23d7ca22988267.png)\n\n$$ X_2 \\lt X_3 \\lt X_1 \u003c X_4 $$\n\n```py\nordering = [2, 3, 1, 4]\nprint(ordering)\na = BDD(f, ordering)\na.displayGraph()\n```\n\n\u003e Output:\n\n```\n[2, 3, 1, 4]\n```\n\n![](./img/e003caf16b860b0c6162480f7437355ab6eb5f3f.png)\n\n## Example 2\n\nBoolean Function:\n$$f(X_1, X_2,, X_8) = X_1.X_2 + X3.X_4 + X_5.X_6 + X_7.X_8$$\n\nVariable Orderings:\n\n1.  $X_1 \\lt X_3 \\lt X_5 \\lt X_7 \\lt X_2 \\lt X_4 \\lt X_6 \\lt X_8$\n2.  $X_1 \\lt X_2 \\lt X_3 \\lt X_4 \\lt X_5 \\lt X_6 \\lt X_7 \\lt X_8$\n    :::\n\n```python\nf = boolfunc.Expression(r\"input\\2.pcn\")\nprint(f)\n```\n\n\u003e Output\n\n```\n8\n4\n2 1 2\n2 7 8\n2 3 4\n2 5 6\n```\n\n```python\nordering = [1,3,5,7,2,4,6,8]\nprint(ordering)\na = BDD(f, ordering)\na.displayGraph()\n```\n\n\u003e Output\n\n```\n[1, 3, 5, 7, 2, 4, 6, 8]\n```\n\n![](./img/676733707e51d12539e617326a016f978d4f64ca.png)\n\n```python\nordering = [1,2,3,4,5,6,7,8]\nprint(ordering)\na = BDD(f, ordering)\na.displayGraph()\n```\n\n\u003e Output\n\n```\n[1, 2, 3, 4, 5, 6, 7, 8]\n```\n\n![](./img/83e9644d0b5af21facd01a6c8c78971f9a765b9b.png)\n\n## Example 3\n\nFor this example, we shall see a Boolean function in which the top variable is redundant, and we shall verify that the root node that is obtained in the OBDD is eliminated in the final ROBDD.\n\nBoolean Function:\n$$f(X_1, X_2, X_3) = X_1.X_2.X_3 + X_2.X_3 + \\overline{X_1}.X_2.X_3$$\n\nVariable Ordering:\n\n$$X_1 \\lt X_2 \\lt X_3 $$\n\n```python\nf = boolfunc.Expression(\n    r\"input\\3.pcn\")\nprint(f)\n```\n\n\u003e Output\n\n```\n3\n3\n2 2 3\n3 1 2 3\n3 -1 2 3\n```\n\n```python\nordering = [1,2,3]\nprint(ordering)\na = BDD(f, ordering)\na.display_Graph()\n```\n\n\u003e Output\n\n```\n[1, 2, 3]\n```\n\n![](./img/b086d0e0-0176-48b7-8a35-45ad2e195056.png)\n\nWe see that the root node(i.e variable $X_1$) is eliminated. The simplified boolean expression represented by the ROBDD is\n\n$$f(X_1, X_2, X_3) = X_2.X_3$$\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-pinbo%2Frobdd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthe-pinbo%2Frobdd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-pinbo%2Frobdd/lists"}