{ "cells": [ { "cell_type": "markdown", "id": "Nti1VE8-Dl_5", "metadata": { "id": "Nti1VE8-Dl_5" }, "source": [ "# BoolForge Tutorial #1: Working with Boolean functions\n", "\n", "In this tutorial, we will explore the `BooleanFunction` class — the foundation of BoolForge.\n", "You will learn how to:\n", "- create Boolean functions from truth tables and text expressions,\n", "- compute basic properties such as degree and bias, and\n", "- convert between truth tables, logical expressions, polynomials, and the CANA package." ] }, { "cell_type": "code", "execution_count": 3, "id": "d6aba3ec", "metadata": { "executionInfo": { "elapsed": 8118, "status": "ok", "timestamp": 1729274660920, "user": { "displayName": "Bernard Lidicky", "userId": "15999393152596956268" }, "user_tz": 300 }, "id": "d6aba3ec" }, "outputs": [], "source": [ "import boolforge\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "2901dee5", "metadata": { "id": "2901dee5" }, "source": [ "## Create a Boolean function \n", "\n", "Boolean functions can be described in logical form, as polynomials, or as truth tables. BoolForge treats Boolean functions as binary vectors of length $2^n$, where n is the number of inputs. The vectors describe the right side of the truth table. The left side of the truth table is not stored because it is the same for any function with n inputs. For example, the function f(A,B) = A AND B is stored as [0,0,0,1], which is exactly the right side of the truth table\n", "
\n", "\n", "| A | B | f(A,B) |\n", "| :-: | :-: | :-: |\n", "| 0 | 0 | 0 |\n", "| 0 | 1 | 0 |\n", "| 1 | 0 | 0 |\n", "| 1 | 1 | 1 |\n", "\n", "
\n", "\n", "### Create a Boolean function from truth table\n", "\n", "An instance of `BooleanFunction` can be generated by specifying the right side of the truth table, i.e., by providing a binary vector of length $2^n$ for any $n\\geq 0$. For example, to create the AND function above, we can write" ] }, { "cell_type": "code", "execution_count": 4, "id": "67a5a393", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f [0 0 0 1]\n" ] } ], "source": [ "# Define a simple Boolean function f(A,B) = A AND B with optional name 'f_AND'\n", "f = boolforge.BooleanFunction([0, 0, 0, 1], name=\"f_AND\")\n", "print('f',f)" ] }, { "cell_type": "markdown", "id": "1d2108ff", "metadata": {}, "source": [ "### Create a Boolean function from text\n", "\n", "Instances of `BooleanFunction` can also be created from text. For example, to define the same function as f, we can write" ] }, { "cell_type": "code", "execution_count": 5, "id": "a1a56603", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f2 [0 0 0 1]\n" ] } ], "source": [ "f2 = boolforge.BooleanFunction('A and B')\n", "print('f2',f2)" ] }, { "cell_type": "markdown", "id": "99660fd9", "metadata": {}, "source": [ "The text processor is fairly versatile. For example, we can define the same function as f also by writing\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "658b4eee", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f3 [0 0 0 1]\n" ] } ], "source": [ "f3 = boolforge.BooleanFunction('A + B > 1')\n", "print('f3',f3)" ] }, { "cell_type": "markdown", "id": "3aa686f7", "metadata": {}, "source": [ "Some examples of more complicated functions include" ] }, { "cell_type": "code", "execution_count": 14, "id": "10f142b1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x1\tx2\tx3\t|\tg\th\tk\n", "-------------------------------------------------\n", "0\t0\t0\t|\t0\t1\t0\n", "0\t0\t1\t|\t1\t0\t1\n", "0\t1\t0\t|\t0\t0\t1\n", "0\t1\t1\t|\t1\t1\t0\n", "1\t0\t0\t|\t0\t0\t1\n", "1\t0\t1\t|\t0\t1\t0\n", "1\t1\t0\t|\t1\t1\t1\n", "1\t1\t1\t|\t1\t0\t1\n" ] } ], "source": [ "# Define a 3-input function without any symmetries\n", "g = boolforge.BooleanFunction('(A AND B) OR (NOT A AND C)')\n", "\n", "# Define a 3-input linear / parity function \n", "h = boolforge.BooleanFunction('(x + y + z) % 2 == 0')\n", "\n", "# Define a 3-input threshold function\n", "k = boolforge.BooleanFunction('x + y - z > 0')\n", "\n", "labels = ['g','h','k']\n", "boolforge.display_truth_table(g,h,k,labels=labels)" ] }, { "cell_type": "markdown", "id": "19eabf59", "metadata": {}, "source": [ "## Attributes of BooleanFunction\n", "\n", "Every instance of `BooleanFunction` has five attributes:\n", "
\n", "\n", "| attribute | data type | description | \n", "| :-: | :-: | :- | \n", "| f | np.array(int) | stores the Boolean function (the right side of its truth table) |\n", "| n | int | the degree, i.e., the number of variables |\n", "| variables | np.array(str) | the name of the variables. By default, $x_0, \\ldots, x_{n-1}$ | \n", "| name | str | optional, default '' |\n", "| properties | dict | stores certain properties of the function as they are computed |\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 8, "id": "c465afaa", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f.f [0 0 0 1]\n", "f.n 2\n", "f.variables ['x0' 'x1']\n", "f.name f_AND\n", "f.properties {}\n" ] } ], "source": [ "print('f.f',f.f)\n", "print('f.n',f.n)\n", "print('f.variables',f.variables)\n", "print('f.name',f.name)\n", "print('f.properties',f.properties)" ] }, { "cell_type": "markdown", "id": "01d51966", "metadata": {}, "source": [ "Since `f` was generated from truth table, its variables default to $x_0, x_1$. On the contrary, generating instances of `BooleanFunction` from text also provides the variable names. This becomes important when reading from text files entire Boolean networks, i.e., collections of Boolean functions. For example, for `f2`, `f3`, `g`, and `h`, we have:" ] }, { "cell_type": "code", "execution_count": 9, "id": "dcd1f643", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f2.variables ['A' 'B']\n", "f3.variables ['A' 'B']\n", "g.variables ['A' 'B' 'C']\n", "h.variables ['x' 'y' 'z']\n" ] } ], "source": [ "print('f2.variables',f2.variables)\n", "print('f3.variables',f3.variables)\n", "print('g.variables',g.variables)\n", "print('h.variables',h.variables)\n" ] }, { "cell_type": "markdown", "id": "ab0907e0", "metadata": {}, "source": [ "The variable order is determined by the first occurence of the variable in the generating text. See e.g.," ] }, { "cell_type": "code", "execution_count": 10, "id": "052bc4a8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['x' 'y' 'z']\n", "['y' 'z' 'x']\n" ] } ], "source": [ "print(boolforge.BooleanFunction('(x + y + z) % 2 == 0').variables)\n", "print(boolforge.BooleanFunction('(y + z + x) % 2 == 0').variables)" ] }, { "cell_type": "markdown", "id": "ac35b266", "metadata": {}, "source": [ "## Basic properties of Boolean functions\n", "\n", "We can inspect various properties of a Boolean function. The degree, i.e., the number of inputs, is readily available via 'f.n'. Other properties can be computed." ] }, { "cell_type": "code", "execution_count": 11, "id": "1bca389f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of variables: 2\n", "Is constant? False\n", "Is degenerated? False\n", "Indices of essential variables: [0, 1]\n", "Type of inputs: ['positive' 'positive']\n", "Hamming weight: 1\n", "Absolute bias: 0.5\n" ] } ], "source": [ "print(\"Number of variables:\", f.n)\n", "print(\"Is constant?\", f.is_constant())\n", "print(\"Is degenerate?\", f.is_degenerate())\n", "print(\"Indices of essential variables:\", f.get_essential_variables())\n", "print(\"Type of inputs:\", f.get_type_of_inputs())\n", "print(\"Hamming weight:\", f.get_hamming_weight())\n", "print(\"Absolute bias:\", f.get_absolute_bias())" ] }, { "cell_type": "markdown", "id": "98eb5d7f", "metadata": {}, "source": [ "Rerunning the above code for `g` helps understand the different properties. \n", "- 'g.is_constant()' checks if the function is constant, \n", "- 'g.is_degenerate()' checks if the function contains non-essential variables, \n", "- 'g.get_essential_variables()' provides the indices (Python: starting at 0!) of the essential variables, \n", "- 'g.get_type_of_inputs()' describes the type of each input ('increasing','decreasing','conditional', or 'non-essential').\n", "- The Hamming weight is the number of 1s in the right side of the truth table.\n", "- The absolute bias is 0 if the function is unbiased, i.e., if the number of 0s is equal to the number of 1s, and it is 1 for constant functions. \n" ] }, { "cell_type": "code", "execution_count": 12, "id": "cebd1b83", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of variables: 3\n", "Is constant? False\n", "Is degenerated? False\n", "Indices of essential variables: [0, 1, 2]\n", "Type of inputs: ['positive' 'positive' 'conditional']\n", "Hamming weight: 4\n", "Absolute bias: 0.0\n" ] } ], "source": [ "print(\"Number of variables:\", g.n)\n", "print(\"Is constant?\", g.is_constant())\n", "print(\"Is degenerate?\", g.is_degenerate())\n", "print(\"Indices of essential variables:\", g.get_essential_variables())\n", "print(\"Type of inputs:\", g.get_type_of_inputs())\n", "print(\"Hamming weight:\", g.get_hamming_weight())\n", "print(\"Absolute bias:\", g.get_absolute_bias())" ] }, { "cell_type": "markdown", "id": "57fcf15d", "metadata": {}, "source": [ "## Convert to logical and polynomial expression\n", "\n", "While Boolean functions are stored as truth tables, they can be expressed in logical and polynomial format." ] }, { "cell_type": "code", "execution_count": 13, "id": "1e18a526", "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'BooleanFunction' object has no attribute 'to_logical'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[13], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mLogical form of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mf\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[43mf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_logical\u001b[49m(AND\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m ∧ \u001b[39m\u001b[38;5;124m'\u001b[39m, OR\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m ∨ \u001b[39m\u001b[38;5;124m'\u001b[39m, NOT\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m ¬\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPolynomial form of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mf\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m:\u001b[39m\u001b[38;5;124m\"\u001b[39m, f\u001b[38;5;241m.\u001b[39mto_polynomial())\n", "\u001b[0;31mAttributeError\u001b[0m: 'BooleanFunction' object has no attribute 'to_logical'" ] } ], "source": [ "print(f\"Logical form of {f.name}:\", f.to_logical(AND=' ∧ ', OR=' ∨ ', NOT=' ¬'))\n", "print(f\"Polynomial form of {f.name}:\", f.to_polynomial())" ] }, { "cell_type": "markdown", "id": "14cedb00", "metadata": {}, "source": [ "In addition, an instance of `BooleanFunction` can be turned into an instance of `BooleanNode` from the [CANA package](https:www.github.com). This requires the optional CANA package to be installed." ] }, { "cell_type": "code", "execution_count": 63, "id": "85cb6c23", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "cana_object = f.to_cana()\n", "print(type(cana_object))" ] } ], "metadata": { "colab": { "provenance": [ { "file_id": "1uYGafWSuMhd9QxcQkz2tTMTeFsLb_VHA", "timestamp": 1696210918065 } ] }, "kernelspec": { "display_name": "envpy312", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }