{ "cells": [ { "cell_type": "markdown", "id": "021b3a2f", "metadata": {}, "source": [ "# BoolForge Tutorial 4: Random Boolean Function Generation\n", "\n", "This tutorial focuses on the random generation of Boolean functions with\n", "prescribed properties, enabling large-scale computational studies.\n", "\n", "Random Boolean function generation enables:\n", "1. Null model comparisons: Are biological networks special?\n", "2. Ensemble studies: How do structural properties affect dynamics?\n", "3. Robustness testing: Sample the space of equivalent models\n", "4. Theoretical predictions: Derive expected values for network properties\n", "\n", "## What you will learn\n", "In this tutorial you will learn how to generate random Boolean functions with:\n", "\n", "- specified canalizing properties (depth, layer structure),\n", "- bias, absolute bias, or a specific Hamming weight,\n", "- linearity constraints,\n", "- degeneracy constraints.\n", "\n", "It is strongly recommended to complete the previous tutorials first.\n", "\n", "---\n", "## 0. Setup" ] }, { "cell_type": "code", "execution_count": 1, "id": "0241af58", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:49.691208Z", "iopub.status.busy": "2026-01-15T21:27:49.690875Z", "iopub.status.idle": "2026-01-15T21:27:50.504632Z", "shell.execute_reply": "2026-01-15T21:27:50.504347Z" }, "lines_to_next_cell": 2 }, "outputs": [], "source": [ "import boolforge\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "2f5cdbf6", "metadata": {}, "source": [ "---\n", "## 1. Generating random Boolean functions\n", "\n", "The function `boolforge.random_function(n, *args)` generates a random $n$-input\n", "Boolean function subject to optional constraints. By default, it generates a\n", "**non-degenerate** function, meaning that all variables are essential." ] }, { "cell_type": "code", "execution_count": 2, "id": "94b545bf", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.505999Z", "iopub.status.busy": "2026-01-15T21:27:50.505872Z", "iopub.status.idle": "2026-01-15T21:27:50.770599Z", "shell.execute_reply": "2026-01-15T21:27:50.770362Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x0\tx1\tx2\t|\tf_random_non_degenerate\n", "-------------------------------------------------------\n", "0\t0\t0\t|\t1\n", "0\t0\t1\t|\t1\n", "0\t1\t0\t|\t0\n", "0\t1\t1\t|\t1\n", "1\t0\t0\t|\t1\n", "1\t0\t1\t|\t0\n", "1\t1\t0\t|\t1\n", "1\t1\t1\t|\t1\n", "Is f degenerate? False\n", "Activities of f: [0.5 0.5 0.5]\n", "Edge effectiveness of f: [0.75, 0.75, 0.75]\n" ] } ], "source": [ "n = 3\n", "f = boolforge.random_function(n)\n", "\n", "boolforge.display_truth_table(f, labels=\"f_random_non_degenerate\")\n", "\n", "print(\"Is f degenerate?\", f.is_degenerate())\n", "print(\"Activities of f:\", f.get_activities(EXACT=True))\n", "print(\"Edge effectiveness of f:\", f.get_edge_effectiveness())" ] }, { "cell_type": "markdown", "id": "8060a88d", "metadata": { "lines_to_next_cell": 2 }, "source": [ "The rest of this tutorial describes the various constraints. \n", "Each constraint defines a specific family of n-input Boolean functions, \n", "from which `boolforge.random_function(n,*args)` samples *uniformly at random*. \n", "That is, each function satisfying a given set of constraints is selected with equal probability." ] }, { "cell_type": "markdown", "id": "2dc2dc6d", "metadata": {}, "source": [ "---\n", "## 2. Linear functions\n", "\n", "Setting `LINEAR=True` generates *linear* functions (also known as *parity* functions)." ] }, { "cell_type": "code", "execution_count": 3, "id": "b5cd8da3", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.771888Z", "iopub.status.busy": "2026-01-15T21:27:50.771756Z", "iopub.status.idle": "2026-01-15T21:27:50.774296Z", "shell.execute_reply": "2026-01-15T21:27:50.774081Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x0\tx1\tx2\t|\tf_linear\n", "----------------------------------------\n", "0\t0\t0\t|\t1\n", "0\t0\t1\t|\t0\n", "0\t1\t0\t|\t0\n", "0\t1\t1\t|\t1\n", "1\t0\t0\t|\t0\n", "1\t0\t1\t|\t1\n", "1\t1\t0\t|\t1\n", "1\t1\t1\t|\t0\n", "Activities: [1. 1. 1.]\n", "Edge effectiveness: [1.0, 1.0, 1.0]\n", "Normalized average sensitivity: 1.0\n", "Canalizing strength: 0.0\n" ] } ], "source": [ "f = boolforge.random_function(n, LINEAR=True)\n", "\n", "boolforge.display_truth_table(f, labels=\"f_linear\")\n", "\n", "print(\"Activities:\", f.get_activities(EXACT=True))\n", "print(\"Edge effectiveness:\", f.get_edge_effectiveness())\n", "print(\"Normalized average sensitivity:\", f.get_average_sensitivity(EXACT=True))\n", "print(\"Canalizing strength:\", f.get_canalizing_strength())\n", "\n", "# Linear functions are the only Boolean functions with activity 1 (for all variables),\n", "# normalized average sensitivity 1 and canalizing strength 0." ] }, { "cell_type": "markdown", "id": "18231f23", "metadata": {}, "source": [ "---\n", "## 3. Functions with prescribed canalizing properties\n", "\n", "If `LINEAR=False` (default), the canalizing layer structure can be specified\n", "via `layer_structure`. This specifies the number of conditionally canalizing variables in each layer of the randomly generated function. \n", "If the optional argument `EXACT_DEPTH=True` (default is False), \n", "then this describes the exact layer structure, i.e., the core function cannot be canalizing.\n", "If `EXACT_DEPTH=False` (the default), it is possible that the core function is canalizing, \n", "meaning that the last described layer in `layer_structure` may have more conditionally canalizing variables, \n", "or that there are additional canalizing layers. \n", "\n", "Before generating any random function, `random_function()` goes through a number of checks \n", "ensuring that the provided optional arguments make sense. \n", "For example, it checks that the provided layer structure $(k_1,\\ldots,k_r)$ satisfies\n", "- $k_i\\geq 1$, \n", "- $k_1 + \\cdots + k_r \\leq n$, and\n", "- if $k_1 + \\cdots + k_r = n$, then $k_r \\geq 2$ because the last layer of a nested canalizing function must always contain two or more variables." ] }, { "cell_type": "code", "execution_count": 4, "id": "7c50613b", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.775305Z", "iopub.status.busy": "2026-01-15T21:27:50.775234Z", "iopub.status.idle": "2026-01-15T21:27:50.778633Z", "shell.execute_reply": "2026-01-15T21:27:50.778442Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x0\tx1\tx2\t|\tf\tg\th\tk\n", "---------------------------------------------------------\n", "0\t0\t0\t|\t1\t0\t0\t1\n", "0\t0\t1\t|\t0\t0\t0\t0\n", "0\t1\t0\t|\t1\t1\t0\t1\n", "0\t1\t1\t|\t0\t0\t1\t0\n", "1\t0\t0\t|\t1\t0\t0\t1\n", "1\t0\t1\t|\t0\t0\t0\t0\n", "1\t1\t0\t|\t1\t0\t0\t1\n", "1\t1\t1\t|\t1\t1\t0\t1\n", "Canalizing depth of f: 3\n", "Layer structure of f: [1, 2]\n", "Number of layers of f: 2\n", "Core function of f: [1]\n", "\n", "Canalizing depth of g: 1\n", "Layer structure of g: [1]\n", "Number of layers of g: 1\n", "Core function of g: [1 0 0 1]\n", "\n", "Canalizing depth of h: 3\n", "Layer structure of h: [3]\n", "Number of layers of h: 1\n", "Core function of h: [1]\n", "\n", "Canalizing depth of k: 3\n", "Layer structure of k: [1, 2]\n", "Number of layers of k: 2\n", "Core function of k: [1]\n", "\n" ] } ], "source": [ "f = boolforge.random_function(n, layer_structure=[1])\n", "g = boolforge.random_function(n, layer_structure=[1], EXACT_DEPTH=True)\n", "h = boolforge.random_function(n, layer_structure=[3])\n", "k = boolforge.random_function(n, layer_structure=[1, 2])\n", "\n", "labels = [\"f\", \"g\", \"h\", \"k\"]\n", "boolforge.display_truth_table(f, g, h, k, labels=labels)\n", "\n", "for func, label in zip([f, g, h, k], labels):\n", " info = func.get_layer_structure()\n", " print(f\"Canalizing depth of {label}: {func.get_canalizing_depth()}\")\n", " print(f\"Layer structure of {label}: {info['LayerStructure']}\")\n", " print(f\"Number of layers of {label}: {info['NumberOfLayers']}\")\n", " print(f\"Core function of {label}: {info['CoreFunction']}\")\n", " print()" ] }, { "cell_type": "markdown", "id": "dcec83cc", "metadata": {}, "source": [ "Repeated evaluation of this block of code shows that the canalizing depth of `f` is either 1 or 3\n", "(note that a canalizing depth of $n-1$ is never possible for a non-degenerate function). \n", "On the contrary, the canalizing depth of `g` is always 1 because we set `EXACT_DEPTH=True`. \n", "The 2-input core function of `g` is one of the two linear functions, each with 50% probability. \n", "Likewise, the core function for the other functions is simply [0] or [1], each with 50% probability. \n", "Functions `h` and `k` are nested canalizing, i.e., their canalizing depth is 3. \n", "Their layer structure is exactly as specified.\n", "\n", "If we do not care about the specific layer structure but only about the canalizing depth, \n", "we specify the optional argument `depth` instead of `layer_structure`." ] }, { "cell_type": "code", "execution_count": 5, "id": "7bba6420", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.779621Z", "iopub.status.busy": "2026-01-15T21:27:50.779556Z", "iopub.status.idle": "2026-01-15T21:27:50.782063Z", "shell.execute_reply": "2026-01-15T21:27:50.781870Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x0\tx1\tx2\t|\tf\tg\th\tk\n", "---------------------------------------------------------\n", "0\t0\t0\t|\t1\t1\t1\t0\n", "0\t0\t1\t|\t0\t1\t0\t0\n", "0\t1\t0\t|\t0\t0\t1\t0\n", "0\t1\t1\t|\t0\t0\t1\t0\n", "1\t0\t0\t|\t0\t0\t0\t1\n", "1\t0\t1\t|\t0\t1\t1\t0\n", "1\t1\t0\t|\t1\t1\t1\t0\n", "1\t1\t1\t|\t0\t1\t1\t0\n", "Canalizing depth of f: 1\n", "\n", "Canalizing depth of g: 0\n", "\n", "Canalizing depth of h: 1\n", "\n", "Canalizing depth of k: 3\n", "\n" ] } ], "source": [ "# any function has at least canalizing depth 0 so this is the same as boolforge.random_function(n)\n", "f = boolforge.random_function(n,depth=0)\n", "\n", "# a random non-canalizing function\n", "g = boolforge.random_function(n,depth=0,EXACT_DEPTH=True)\n", "\n", "# a random canalizing function\n", "h = boolforge.random_function(n,depth=1)\n", "\n", "# a random nested canalizing function\n", "k = boolforge.random_function(n,depth=n)\n", "\n", "labels = [\"f\", \"g\", \"h\", \"k\"]\n", "boolforge.display_truth_table(f, g, h, k, labels=labels)\n", "\n", "for func, label in zip([f, g, h, k], labels):\n", " print(f\"Canalizing depth of {label}: {func.get_canalizing_depth()}\")\n", " print()" ] }, { "cell_type": "markdown", "id": "afff7b66", "metadata": {}, "source": [ "Repeated evaluation of this block of code shows that the canalizing depth of `f` can be 0, 1, or 3. \n", "Note that specifying `depth=0` without `EXACT_DEPTH=True` does not restrict the space of functions at all. \n", "On the contrary, the canalizing depth of `g` is always 0 (i.e., g does not contain any canalizing variables) because we set `EXACT_DEPTH=True`.\n", "Function `h` is canalizing and may be nested canalizing (because we specified that the minimal canalizing depth is 1), \n", "and `k` is always nested canalizing (i.e., it has canalizing depth $n=3$).\n", "\n", "We remember: If `EXACT_DEPTH=True`, `depth` is interpreted as exact canalizing depth. \n", "Otherwise (default), `depth` is interpreted as minimal canalizing depth. \n", "For example,\n", "\n", "- `depth=1`: \"At least 1-canalizing\" (could be 2,3,...,n-canalizing)\n", "- `depth=1, EXACT_DEPTH=True`: \"Exactly 1-canalizing\" (not 2,3,...,n-canalizing)" ] }, { "cell_type": "markdown", "id": "3725fd9d", "metadata": {}, "source": [ "---\n", "## 4. Allowing degenerate functions\n", "\n", "It is possible that an n-input Boolean function does not depend on all its variables.\n", "For example, the function $f(x,y) = x$ depends on $x$ but not on $y$. \n", "By default, such degenerate functions are never generated by `boolforge.random_function()`.\n", "To enable the generation of possibly degenerate functions, we set `ALLOW_DEGENERATE_FUNCTIONS=True`.\n", "Although hardly of any practical value, we can even restrict the random generation to degenerate functions only, using `boolforge.random_degenerate_function(n,*args)`. \n", "\n", "Since degenerate functions occur much more frequently at low degree, we set `n=2`, \n", "generate a large number of random, possibly degenerate functions and \n", "compare a histogram of the observed number of essential variables to the expected proportions." ] }, { "cell_type": "code", "execution_count": 6, "id": "5e31b213", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.783049Z", "iopub.status.busy": "2026-01-15T21:27:50.782991Z", "iopub.status.idle": "2026-01-15T21:27:50.966906Z", "shell.execute_reply": "2026-01-15T21:27:50.966714Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error: [ 0.0002 0.003 -0.0032]\n" ] }, { "data": { "image/png": "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79/vvF976qZOnUq4AbIowg3hRiwON5auUAzfOHz4sAkDujWFK51BVrduXXP94Ycflk8++USmTJkic+fOdQYbV64BQ0OHhhWthVJ79+6VH3/8UZYsWeJ8jOZiHVbSHpqffvrJhB8NO75st55ft+ZIq50AAKRGuLGBS5cumf9qzYzut+VKa1+UhghdEVoDyKFDhzJ0jqeeesrU2aR21113maDij3YDAOAtwo0NVK9e3YQBHRpKq+dE61R0+vxXX30l999/v6mbadWqldtjtm3bZoKK0iEfrbfROhx19913y88//2zqdzzRmh7txdmwYYPHYSnHVH3XrTLS0249v267kbqdAACkhXBjA4UKFZIRI0bI0KFDTcC49957zZikFgzruKQumKibjmqxr4aUkSNHSlRUlBlm0tlLDhMmTJBixYqZ2Wq68rM+z7EGkc6C0hlUWkSsNTEFChQwYUdrbF5//XWzgam+Zu/eveW1114zBcVatBwfH29qdsqXL29mSa1YscKEKy0o/rt26+tpcbFusaFt1vNq75PWAQEAYIvtF5C2iRMnmr22dFq19na0a9fODPdo6OjTp4+MGzfOBBs1fvx4E2A0OLjSehydTaWLK+qqz1988YWzx0WniGuvjPbm6HRwrYnRqeRlypRxPl9reXRm1IABA6Rq1apmx3fHVHEddtLzajGwntuxUGNa7dap4Up7kj766CP59NNPTWDSrTZ0bSMAANLCbCmwejAAn2K2FLOlxOLZUvTcAAAAWyHcAAAAW6GgGNKiRQvn1gwAAAQ6em4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICtEG4AAICt+CTcXLhwwRcvAwAAkPnhZurUqRIbG+u83a1bNylWrJiULVtW9u7de/stAgAAyMxwM2/ePAkNDTXXv/nmG3P56quvpH379jJy5MjbaQsAAMBty+XtE06dOuUMNytWrDA9N23atJGwsDBp1KjR7bcIAAAg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8SR1YNGViVNSUjKpZQAAIBBZvv0CAACALxFuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArRBuAACArWSJcDNnzhwJCwuT4OBgadSokWzfvv2Wj//www+latWq5vG1atWSL7/8MtPaCgAAsjbLw01sbKwMGzZMxo4dK7t27ZLw8HBp27atxMfHe3z8li1bpEePHtKnTx/ZvXu3dO7c2Vz27duX6W0HAABZj+XhZsaMGdKvXz+Jjo6W6tWry7x58yR//vwyf/58j4+fNWuWtGvXTkaOHCnVqlWTiRMnyt133y2vv/56prcdAABkPbmsPPm1a9dk586dMnr0aOexHDlySGRkpGzdutXjc/S49vS40p6eTz/91OPjr169ai4OCQkJ5r+JiYniD8lXr0h2lhiUYnUTrOen71Z68R3kO8h30Fp8B8Uv30HH73ZKSkrWDjdnz56VpKQkKVmypNtxvf3LL794fM6pU6c8Pl6PezJ58mQZP378TcdDQ0Nvq+3wrLDVDcgKpvApWIlPn++g1fj0xa/fwYsXL0rhwoWzbrjJDNor5NrTk5ycLOfOnZNixYpJUFCQpW2zG03VGhrj4uIkJCTE6uYgG+I7CKvxHfQf7bHRYFOmTJm/fayl4aZ48eKSM2dOOX36tNtxvV2qVCmPz9Hj3jw+b9685uKqSJEit912pE3/B83/qGElvoOwGt9B//i7HpssUVCcJ08eqVevnqxZs8atZ0VvR0REeHyOHnd9vPrmm2/SfDwAAMheLB+W0iGjqKgoqV+/vjRs2FBiYmLk8uXLZvaU6tWrl5QtW9bUzqghQ4ZI8+bNZfr06dKhQwdZtmyZ7NixQ9566y2L3wkAAMgKLA833bt3lzNnzsiYMWNMUXCdOnVk1apVzqLh48ePmxlUDo0bN5alS5fKv/71L3nhhRekcuXKZqZUzZo1LXwXUDr8p+sVpR4GBDIL30FYje9g1hCUkp45VQAAAAHC8kX8AAAAfIlwAwAAbIVwAwAAbIVwAwAAbIVwA5+ZM2eOhIWFSXBwsDRq1Ei2b99udZOQTWzcuFE6duxoVi7VlcfT2msO8BddrqRBgwZSqFAhKVGihHTu3FkOHjxodbOyLcINfCI2NtasWaRTIHft2iXh4eFmQ9P4+Hirm4ZsQNfG0u+cBmzAChs2bJCBAwfKtm3bzMKy169flzZt2pjvJjIfU8HhE9pTo/9qef31150rTev+KoMHD5ZRo0ZZ3TxkI9pz88knn5h/OQNW0fXbtAdHQ0+zZs2sbk62Q88Nbtu1a9dk586dEhkZ6TymCy/q7a1bt1raNgCwQkJCgvlv0aJFrW5KtkS4wW07e/asJCUlOVeVdtDbuuo0AGQn2nP97LPPSpMmTVg9P7tuvwAAgJ1o7c2+fftk06ZNVjcl2yLc4LYVL15ccubMKadPn3Y7rrdLlSplWbsAILMNGjRIVqxYYWbwlStXzurmZFsMS+G25cmTR+rVqydr1qxx65bV2xEREZa2DQAyg87N0WCjxexr166VChUqWN2kbI2eG/iETgOPioqS+vXrS8OGDSUmJsZMgYyOjra6acgGLl26JIcPH3bePnr0qOzZs8cUc951112Wtg3ZZyhq6dKl8tlnn5m1bhz1hoULF5Z8+fJZ3bxsh6ng8BmdBv7qq6+a/1HXqVNHXnvtNTNFHPC39evXS8uWLW86roF74cKFlrQJ2W8JAk8WLFggTzzxRKa3J7sj3AAAAFuh5gYAANgK4QYAANgK4QYAANgK4QYAANgK4QYAANgK4QYAANgK4QYAANgK4QYAANgK4QYIQMeOHTMrouoWA1nFL7/8Ivfcc48EBwebFarttPqxftYXLlxI93NatGghzz77rFghLCzMbH+SXrqCc5EiRW75mHHjxtnqbwr7I9wAGaDLqesP3pQpU9yOf/rpp2kuw253Y8eOlQIFCsjBgwfdNlENJJ5CSePGjeXkyZNmj6BA8MMPP8iTTz5pdTMASxFugAzSHoqpU6fK+fPnxS6uXbuW4eceOXJE7r33XilfvrwUK1ZM7LTrfalSpbJ8aHX87e68807Jnz+/1c0BLEW4ATIoMjLS/OhNnjzZq+58HTLQoQPXXqDOnTvLyy+/LCVLljRDBBMmTJAbN27IyJEjzc7W5cqVMxvweRoK0p4FDVo1a9aUDRs2uN2/b98+ad++vRQsWNC89uOPPy5nz55166kYNGiQ6a0oXry4tG3b1uP7SE5ONm3SduTNm9e8p1WrVjnv1x/+nTt3msfodX3fab2Ofl4VKlQwOyWHh4fL8uXLnfdrUHz00UfND7TeX7lyZef71h9vbWvp0qXN+9UQ5frZ67BR3759zXNDQkKkVatWsnfv3pv+Fu+99575/LUn5pFHHpGLFy86/w76+c2aNcu8B73o8F/qYak//vhDevToIWXLljUholatWvL+++9Lev3nP/8xr6d/O1czZ86UihUrmutJSUnSp08f5+dUpUoV0y5Xju/NpEmTpEyZMuYxnoalZsyYYdqovWqhoaEyYMAAs4t6atrrqJ+3frb6PYiLi7vl+/j3v/8t1apVM4+vWrWqvPHGG877/u5vBfgb4QbIoJw5c5pAMnv2bDlx4sRtvdbatWvl999/l40bN5ofIx3i+Z//+R+544475Pvvv5f+/fvLU089ddN5NPwMHz5cdu/eLREREdKxY0fz46v0x1h/4OvWrSs7duwwYeT06dPSrVs3t9d49913Te/E5s2bZd68eR7bpz+s06dPl2nTpsmPP/5ofvw6deokhw4dMvfrsE2NGjVMW/T6iBEjPL6O/sAtWrTInGf//v0ydOhQeeyxx5yh7MUXX5Sff/5ZvvrqKzlw4IDMnTvXhC6lu8x//vnn8sEHH5ihryVLlriFxIcfflji4+PNczVo3X333dK6dWs5d+6cW++S/oivWLHCXPS8jqFFfY/6Gfbr18+8B71oGEjtr7/+knr16snKlStNeNQhIA2N27dvT9ff+p///KfUr1/ftN+V3u7Zs6czBGqQ/PDDD83nMWbMGHnhhRfMe3elw3/6WXzzzTfm/XiSI0cO89np561/a/2uPffcc26PuXLliglJ+rfR74F+dzT4pUXbqm3S5+jfSf93oH87ff30/K0Av9NdwQF4JyoqKuWBBx4w1++5556U3r17m+uffPJJiuv/rMaOHZsSHh7u9tyZM2emlC9f3u219HZSUpLzWJUqVVKaNm3qvH3jxo2UAgUKpLz//vvm9tGjR815pkyZ4nzM9evXU8qVK5cydepUc3vixIkpbdq0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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "n = 2\n", "nsim = 10_000\n", "\n", "count_essential = np.zeros(n + 1, dtype=int)\n", "\n", "for _ in range(nsim):\n", " f = boolforge.random_function(n, ALLOW_DEGENERATE_FUNCTIONS=True)\n", " count_essential[f.get_number_of_essential_variables()] += 1\n", "\n", "expected = np.array([2 / 16, 4 / 16, 10 / 16])\n", "\n", "x = np.arange(n + 1)\n", "width = 0.4\n", "\n", "fig, ax = plt.subplots()\n", "ax.bar(x - width / 2, count_essential / nsim, width=width, label=\"observed\")\n", "ax.bar(x + width / 2, expected, width=width, label=\"expected\")\n", "ax.legend(frameon=False)\n", "ax.set_xticks(x)\n", "ax.set_xlabel(\"Number of essential variables\")\n", "ax.set_ylabel(f\"Proportion of {n}-input functions\")\n", "\n", "print(\"Error:\", count_essential / nsim - expected)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "43d5dfca", "metadata": {}, "source": [ "---\n", "## 5. Functions with prescribed Hamming weight\n", "\n", "The Hamming weight of a Boolean function is the number of ones in its truth table.\n", "BoolForge allows for the generation of random n-input functions with a specific Hamming weight $w\\in\\{0,1,\\ldots,2^n\\}$.\n", "The additional optional parameters `ALLOW_DEGENERATE_FUNCTIONS` and `EXACT_DEPTH` \n", "specify whether degenerate and canalizing functions are allowed.\n", "By default, canalizing functions are allowed, while degenerate functions are not. \n", "Since all functions with Hamming weight $w\\in\\{0,1,2^n-1,2^n\\}$ are canalizing, \n", "we require $2\\leq w\\leq 2^n-2$ whenever canalizing functions are not permissible (i.e., whenever`EXACT_DEPTH=True`)." ] }, { "cell_type": "code", "execution_count": 7, "id": "ebffae5c", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.968016Z", "iopub.status.busy": "2026-01-15T21:27:50.967943Z", "iopub.status.idle": "2026-01-15T21:27:50.970438Z", "shell.execute_reply": "2026-01-15T21:27:50.970255Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x0\tx1\tx2\t|\tf\tg\th\n", "-------------------------------------------------\n", "0\t0\t0\t|\t0\t1\t0\n", "0\t0\t1\t|\t1\t1\t0\n", "0\t1\t0\t|\t0\t0\t0\n", "0\t1\t1\t|\t0\t1\t1\n", "1\t0\t0\t|\t1\t0\t1\n", "1\t0\t1\t|\t1\t1\t0\n", "1\t1\t0\t|\t1\t1\t0\n", "1\t1\t1\t|\t1\t0\t0\n", "Hamming weight of f: 5\n", "Canalizing depth of f: 3\n", "Number of essential variables of f: 3\n", "\n", "Hamming weight of g: 5\n", "Canalizing depth of g: 0\n", "Number of essential variables of g: 3\n", "\n", "Hamming weight of h: 2\n", "Canalizing depth of h: 0\n", "Number of essential variables of h: 3\n", "\n" ] } ], "source": [ "n = 3\n", "\n", "f = boolforge.random_function(n, hamming_weight=5)\n", "g = boolforge.random_function(n, hamming_weight=5, EXACT_DEPTH=True)\n", "h = boolforge.random_function(n, hamming_weight=2, ALLOW_DEGENERATE_FUNCTIONS=True)\n", "\n", "labels = [\"f\", \"g\", \"h\"]\n", "boolforge.display_truth_table(f, g, h, labels=labels)\n", "\n", "for func, label in zip([f, g, h], labels):\n", " print(f\"Hamming weight of {label}: {func.get_hamming_weight()}\")\n", " print(f\"Canalizing depth of {label}: {func.get_canalizing_depth()}\")\n", " print(f\"Number of essential variables of {label}: {func.get_number_of_essential_variables()}\")\n", " print()" ] }, { "cell_type": "markdown", "id": "4173d20d", "metadata": { "lines_to_next_cell": 2 }, "source": [ "---\n", "## 6. Biased and absolutely biased functions\n", "\n", "While specifying the Hamming weight fixes the exact number of 1s in the truth table of a generated function, \n", "specifying the bias or absolute bias acts slightly differently. \n", "The bias $p$ describes the probability of selecting a 1 at any position in the truth table and can be modified using the optional argument `bias`. \n", "Instead of specifying the bias, the absolute bias may also be specified. \n", "Unbiased functions generated using $p=0.5$ have an absolute bias of $0$, the default.\n", "If, for example, we set `absolute_bias=0.5` and specify to use absolute bias (`USE_ABSOLUTE_BIAS=True`, default is False), \n", "the bias used to generate the function is either 0.25 or 0.75, both with probability 50%. \n", "Generally, if we set `USE_ABSOLUTE_BIAS=True; absolute_bias=a` for $a\\in [0,1]$, \n", "the bias is either $(1+a)/2$ or $(1-a)/2$, both with probability 50%. \n", "\n", "To display these different modes, we repeatedly generate random Boolean functions \n", "under three different constraints (`f` with bias $p=0.75$, `g` with absolute bias 0.5, and `h` an unbiased function, i.e., with bias $p=0.5$), \n", "and compare the empirical Hamming weight distribution of the three families of functions." ] }, { "cell_type": "code", "execution_count": 8, "id": "1b7c4baa", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:50.971394Z", "iopub.status.busy": "2026-01-15T21:27:50.971336Z", "iopub.status.idle": "2026-01-15T21:27:51.469143Z", "shell.execute_reply": "2026-01-15T21:27:51.468918Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "data": { "image/png": "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pkGbunv3rmzZssUEY+rnn3+Wjh07Sq9evczzPvjgAxOMjBo1KtbzJ6RM//73v83r27Fjh6ROndoEeqp169bSt29fKVmypGle00W3AYhFUk9HD8B3hIWFOVKlSuV47LHHPJZ06dI59Ovi77//jvO5DRs2dPTt29e1XqNGDUe1atVc6/fu3TPn6tChg2vbmTNnzHm3bNli1jds2GDW161b5zpm9OjRZtuRI0dc21599VVHvXr1PK7Vq1cv13r+/Pkd7du3d61HRUU5goKCHDNnzjTr+n+2bNkcN2/edB0ze/Zsc53du3fH+vr0HPqczz//3KyXLVvWlC1Xrlxm/ZdffnEEBAQ4rl+/btZr167t+M9//uNxjoULFzqCg4Nd63q9r7766oHLFNv7s3r1arPN+byhQ4c6ypQpE+trAPB/qAEC4OG5554zTS7uy0cffeRxTGRkpKmh0NoKzb8JDAw0zVYnTpzwOK506dKux6lSpZJs2bKZ5zhps5jSJq64nqfHaFOPNiG5b4v+nOjcz6FNQZpv43yO1gTpfm1qcqpQoUK859NzVK9e3dT4aDK41upozdLt27flwIEDpkbomWeeMWVV2gz17rvvmvfGuXTr1s3UykSv8UpomdxfW3BwsPn/fu8HAE8kQQPw8Nhjj5ncHHenTp3yWB8/frxMnTrVNEtpQKPP0RycO3fueBwXEBAQI4hw36brKioqKs7nRX+Oc1v050T3MM+5H23e0lwibd7SHCXNR3IGRRoAaTOZ07Vr10w+TvPmzWOcxz3IeRgP8h4CiB81QAASbNOmTdKkSRNp3769lClTxtTO/Pe//5XkomjRohIeHm5qb5y2b99+3+c584A+//xzV66P/r9u3Trznji3KU1+1lodDSajLylTprSsTNGlSZPG1NABiB8BEIAEK1KkiKxdu9YkKe/fv19effVVOXfunCQX2otMa0w0eVvLr813EyZM8KhRiavpSXu0aTK2ewCkvbU0cKlatarr2CFDhsiCBQtMLdAff/xhrrNkyRKPXmJWlCk67QF39OhR03R58eJFj4AKwP8hAAKQYHoT1xqOevXqmQBA82tiG0DRV2nT1cqVK02QoN3OtVeVBiz3a57SQOTZZ581/1erVs0VFOn5tMeZNgU66XuzatUq02NNc4MqVaokkydPlvz581tapuhatGgh9evXN7lcOXLkiDE8AYD/lUIzof//YwCwrUWLFpnxia5evWrGH/IFvlgmwF+QBA3AlrR5SnOXdDBH7bGlY+7oeENJGWj4YpkAf0UABMCWzp49a5qY9H/tSq4DNMY1SKGdywT4K5rAAACA7ZAEDQAAbIcACAAA2A4BEAAAsB0CIAAAYDsEQAAAwHYIgAAAgO0QAAEAANshAAIAAGI3/w+wEHZPO0neOwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "n = 4\n", "nsim = 10_000\n", "\n", "counts = np.zeros((3, 2**n + 1), dtype=int)\n", "\n", "for _ in range(nsim):\n", " f = boolforge.random_function(n, bias=0.75)\n", " g = boolforge.random_function(n, absolute_bias=0.5, USE_ABSOLUTE_BIAS=True)\n", " h = boolforge.random_function(n, absolute_bias=0.5)\n", "\n", " counts[0, f.get_hamming_weight()] += 1\n", " counts[1, g.get_hamming_weight()] += 1\n", " counts[2, h.get_hamming_weight()] += 1\n", "\n", "labels = [\"bias 0.75\", \"absolute bias 0.5\", \"random\"]\n", "x = np.arange(2**n + 1)\n", "width = 0.3\n", "\n", "fig, ax = plt.subplots()\n", "for i, label in enumerate(labels):\n", " ax.bar(x - width + i * width, counts[i] / nsim, width=width, label=label)\n", "\n", "ax.legend(frameon=False)\n", "ax.set_xticks(x)\n", "ax.set_xlabel(\"Hamming weight\")\n", "ax.set_ylabel(f\"Proportion of {n}-input functions\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "313d91aa", "metadata": { "lines_to_next_cell": 2 }, "source": [ "This plot exemplifies the difference between bias and absolute bias:\n", "\n", "- Specifying the bias shifts the mode of the Hamming weight distribution to the value of `bias`.\n", "- Specifying the absolute bias yields random functions with a bimodal Hamming weight distribution. \n", "\n", "Note that `absolute_bias=0.5` is ignored in the generation of `h`. \n", "The desired use of absolute bias must be specified by `USE_ABSOLUTE_BIAS=True`.\n", "\n", "In the above plot, we notice a lack of functions with Hamming weight 0 and $16=2^n$.\n", "These constant functions are degenerate and thus not generated unless we set `ALLOW_DEGENERATE_FUNCTIONS=True`, \n", "which as we see below slightly modifies the resulting Hamming weight distributions." ] }, { "cell_type": "code", "execution_count": 9, "id": "2d128450", "metadata": { "execution": { "iopub.execute_input": "2026-01-15T21:27:51.470262Z", "iopub.status.busy": "2026-01-15T21:27:51.470197Z", "iopub.status.idle": "2026-01-15T21:27:51.937124Z", "shell.execute_reply": "2026-01-15T21:27:51.936872Z" }, "lines_to_next_cell": 2 }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAGwCAYAAABB4NqyAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQ2JJREFUeJzt3QmcjWX/+PGvZca+ZSeMLeugbNmFnyXZH2sxKEWRshTPky08lqwhypNCRKuKsiaFkTWR5UGEGGtMtsHM+b++1+9/zu+cWQ33mXPm3J/363Vz7uXc93XOnDn3d67re11XGofD4RAAAAAbSevrAgAAAKQ0AiAAAGA7BEAAAMB2CIAAAIDtEAABAADbIQACAAC2QwAEAABsJ72vC+CPYmJi5MyZM5ItWzZJkyaNr4sDAADugQ5t+Pfff0uhQoUkbdrE63gIgOKhwU+RIkV8XQwAAHAfTp06JQ8//HCixxAAxUNrfpxvYPbs2X1dHAAAcA8iIyNNBYbzPp4YAqB4OJu9NPghAAIAIHW5l/QVkqABAIDtEAABAADbIQACAAC2QwAEAABshwAIAADYDgEQAACwHQIgAABgOwRAAADAdgiAAACA7RAAAQAA2yEAAgAAtsNcYBYKGbYqxa51YmLLZB3fsGFDqVKlisyYMSPBY0JCQuSVV14xCwAAgYwaILjs2LFDnn/+ea+d3+FwyMiRI6VgwYKSKVMmadKkiRw5ciTR52hQppPaxV5eeuklj+Au9v6+fft67XUAAFI/AiC45M2bVzJnzuy180+ePFnefvttmTdvnvz888+SJUsWadasmdy6dSvRoOzs2bOuZd26dWZ7x44dPY7r06ePx3F6LQAAEkIAZCN3796V/v37S44cOSRPnjwyYsQIUyvjXtvi3kQ2bdo0CQ0NNYFKkSJF5MUXX5Rr16659v/xxx/SqlUryZUrlzmmQoUK8u2338Z7bb2OnvuNN96QNm3aSKVKlWTRokVy5swZWbFiRaJBWYECBVzLypUrpWTJktKgQQOP4zRwcz8ue/bsD/huAQACGTlANrJw4UJ59tlnZfv27bJz507T3FW0aFFTexKftGnTmhqb4sWLy++//24CoNdee03eeecds1+boW7fvi0//vijCYAOHDggWbNmjfdcx48fl4iICNPs5aSBWM2aNSU8PFy6dOmSZPn1Wh999JEMGjTINHO5W7JkidmnwY8GZRrcebM2C4B3ciWTm98I3C8CIBvRWpzp06eb4KFMmTKyb98+s55QAOSeDK21Q+PGjTO5Nc4A6OTJk9KhQwdTS6RKlCiR4LU1+FH58+f32K7rzn1J0ZqiK1euSM+ePT22d+vWTYoVKyaFChWSX3/9VV5//XU5fPiwfPHFF/d0XgCA/RAA2cjjjz/uUXNSq1YtmTp1qkRHR0u6dOniHL9+/XqZMGGCHDp0SCIjI00Tmubr3Lhxw9SuvPzyy9KvXz9Zu3atqdnRYEibtrzl/ffflxYtWphAx5174rYGY5pk3bhxYzl27JhpLgMAIDZygBCvEydOyFNPPWUCms8//1x27dolc+bMcTVFqeeee840jXXv3t3UJlWrVk1mzZoV7/m0aUqdO3fOY7uuO/clRvONNCDTayZFm9XU0aNH7+GVAgDsiADIRrTnlbtt27ZJ6dKl46390YAnJibG1BBpzdEjjzxiEpbja1bTZjFtbho8eLDMnz8/3mtrHpEGOhs2bHBt01olLZPWRCXlgw8+kHz58knLlknnB/zyyy/mf60JAgAgPgRANqI5O5pArPkxH3/8samtGThwYLzHlipVSu7cuWOO0VqexYsXm+7rsXOE1qxZYxKcd+/eLRs3bpRy5crFez5tetPjNY/o66+/NjVGPXr0MM1Zbdu2dR2nTVezZ8/2eK4GYhoAhYWFSfr0nq222sw1duxYE7BprZWeW89bv359rzbHAQBSN3KALOTvvRc0MLh586bUqFHD1Ppo8JPQwIeVK1c23eAnTZokw4cPNwGF5gPpOZw0d0h7gp0+fdp0O2/evLlJqk6I9iC7fv26uaYmM9etW1dWr14tGTNm9AhoLl686PE8bfrS4K13795xzhkcHGz2axd7PbfWSGkukna3BwAgIWkc7gPBwNU0o120r169yngyAGAhusHDX+7fNIEBAADbIQACAAC2QwAEAABshwAIAADYDgEQAACwHQIgAABgOwRAAADAdgiAAACA7RAAwdBpJHS6Cuc8Wt7Qs2dPj2kvUtK9XLthw4Zmug4AQOBjKgwrjc6Rgte6KnagQdmXX36ZIoGTTugaFBTk1WvMmTNH3nrrLYmIiDDTjehcazo1SUI+/PBD6dWrl8e2DBkyyK1bt7xaTgAIdNQAAf/fQw89JNmyZfPa+ZcvX24mox01apSZPFYDoGbNmsn58+cTfZ4O53727FnX8scff3itjABgFwRANqGTjurkozlz5pTcuXPLU089ZSYeje3QoUNSu3ZtM0FpxYoVZdOmTa59f/31lzz99NOSN29eyZQpk5QuXdrM0u6kM7w3atTI7NNr6KSn165dS7BMISEhZhJTd1WqVJHRo0e79qt27dqZmiDnuvrqq6/kscceM+UsUaKEjBkzRu7evZvk+6DHafk1qOjbt6/cvn07wSawxYsXS7Vq1UxQVKBAAenWrZtHsJLU+xGbTi7bp08fU6NTvnx5mTdvnmTOnFkWLFiQaJn1tev1nUv+/PmTfJ0AgMQRANmEzpSutQ87d+6UDRs2SNq0aU1gERMT43Hc0KFDZfDgwbJnzx6pVauWtGrVSi5dumT2jRgxQg4cOCDfffedHDx4UObOnSt58uRxnV9rM3LlyiU7duyQTz/91MzS3r9///sus55HaVChNR/O9Z9++snMSq+z2Wt53n33XdNUNH78+ETPp69by/3DDz/Ixx9/bJq8NCBKyJ07d2Ts2LGyd+9eWbFihcmT0lwip8Tej9g00Nq1a5c0adLEtU1/BroeHh6eaLk1iCxWrJiZ6b5Nmzby22+/JXo8ACBp5ADZRIcOHTzWtdZBay70Bq41PU4asDiP1Ru61hy9//778tprr8nJkyfl0UcfNbUiyr1GZunSpSYvZdGiRZIlSxazbfbs2SaAmjRp0n3VWmj5lNZaac2HkwYtw4YNk7CwMLOuNUAaqGgZtXkpIcHBweZ1a61LhQoV5M033zQBnz5Xg5HYevfu7Xqs13j77belevXqJiDJmjVrou9HbBcvXpTo6Og474Oua61bQsqUKWPKXKlSJTO78ZQpU0wNnQZBDz/8cILPAwAkjhogmzhy5Ih07drV3Mi1+cd5s9abuDut9XFKnz69ublr7Ybq16+fLFu2zDRTabCxdetW17F6jOa0OIMfVadOHVPDdPjwYUtfi9bIaPCiQYhz0aYlrSW6ceNGgs/T8mnw4/5aNZg5depUvMdrjY0GcEWLFjXNYA0aNPB4zxJ7P6yiZdTaLr2GXl9rrTQw1FovAMD9IwCyCb2RX758WebPny8///yzWZR7DkxSWrRoYRJwX331VTlz5ow0btxYhgwZct9l0loXh8MRp9kpKRq0aC2Qdtl3Lpp/pEGe5gRZwdmkp8HikiVLTPOb9kZzf8+S835o01i6dOnk3LlzHtt13b12KynaS01rnY4ePfpArw8A7I4AyAY0h0drYd544w1zky5XrpxJ4I3Ptm3bXI81qVhrQfR4J6190Kanjz76yCQwv/fee2a7HqM1Mxo4OG3ZssUEOdqMEx89l9baOEVGRsrx48fj3PC16cidJj/r6ylVqlScJb6mLCct382bNz1eq9YeaW5NbNospe/bxIkTpV69elK2bNl4e2sl9H7E1/xWtWpVk4fkpLVjuu5e65YUfS802CtYsOA9PwcAEBc5QDagicnaK0tvznrj1CYczaFJaJwa7c2kAc306dNNoOTMhRk5cqS5iWv+TFRUlKxcudIVHGlvKM2/0WBAe3FduHBBBgwYIN27d08w/0d7jGnystZOaZ6Pnl9rSdxpU50GCdqcpuPf6GvR47QXmzZN/eMf/zBBjwY3+/fvl3HjxiX4PmjNzbPPPmsCQU1o1vJqzlN8QZOeW4MWHadHe4vpuTVXyF1i70d8NAld3x9tVtSxfzRg0oDRfZwfbe4qXLiwTJgwwaxrU9/jjz9ugrsrV66YMYS01um5555L8DoAREKGrUp0/4mJLVOsLPBP1ADZgN7gNVdFa3M04VmbbPRGGh+t8dBF82U2b94sX3/9tatnkwYEw4cPNwm59evXN8GKnldpbs2aNWtMM5smCmtgorVNmgidED2X5rVoMNOyZUsz2GHJkiU9jpk6daqsW7fO1NJo04/SpikNNtauXWuupQGCBmvaUyoxWh4N7rTsnTt3ltatW7u63MdXs6PBmfZm0y7r+p5oArK7xN6P+Og19RwaOGlOjzbdaZK5e4Cowal7rZgGoJrfpIHVk08+aWrJNNdIywQAuH9pHLGTMGBuMjly5DC9bjQHBACQumpmqAGyp8hk3L+pAQIAALZDAAQAAGyHAAgAANgOARAAALAdAiAAAGA7BEAAAMB2CIAAAIDtEAABAADbIQACAAC2QwAEr+jZs6eZ2gIAAH/EZKgWCl0YmmLX2he2L8WuBQBAoKEGyMZ0dnQAAOzILwKgOXPmSEhIiGTMmFFq1qwp27dvT/DY+fPnS7169SRXrlxmadKkSZzjdX5XnXG7YMGCkilTJnPMkSNHxO4aNmwo/fv3l1deecXM8K6zqk+bNk1CQ0MlS5YsZsb1F198Ua5du+Z6js6InjNnTjPTu85InjVrVmnevLnHjOXR0dEyaNAgc1zu3LnltddeMz8Dd1FRUfLyyy9Lvnz5zM+5bt26smPHDtf+H374QdKkSWOuo7O+68+tUaNGcv78efnuu+/MtXViu27dusmNGzdS6B0DAAQqnwdAy5cvNzfPUaNGye7du6Vy5crmxqw3vvjojbJr166yceNGCQ8PNzftpk2byp9//uk6ZvLkyfL222/LvHnz5OeffzY3dz3nrVu3xO4WLlwowcHBsmXLFvP+pE2b1rxXv/32m9n3/fffmwDGnQYcU6ZMkcWLF8uPP/4oJ0+elCFDhrj2T5061QRKCxYskM2bN8vly5flyy+/9DiHnvPzzz8319Cfc6lSpczPRI91N3r0aJk9e7Zs3bpVTp06JZ06dZIZM2bI0qVLZdWqVbJ27VqZNWuWl98lAECgS+OI/ad6CtMan+rVq5ubnoqJiTFBzYABA2TYsGFJPl9rH7QmSJ/fo0cPU/NQqFAhGTx4sOsmffXqVcmfP7+5SXfp0iXJc0ZGRkqOHDnM87TWIVBygLQGSF+bBiAJ+eyzz6Rv375y8eJFs67vWa9eveTo0aNSsmRJs+2dd96RN998UyIiIsy6vt+vvvqqDB061KzfvXtXihcvLlWrVpUVK1bI9evXzc9Iz6U1OOrOnTum1k9ro/R5Gtg+8cQTsn79emncuLE5ZuLEiTJ8+HA5duyYlChRwmzTsp04cUJWr16d7NcPwPdChq1KdP+JiS1T1XXgX5Jz/07r6xyUXbt2mSYqV4HSpjXrWrtzL7R2Qm+mDz30kFk/fvy4uTG7n1PfDA20EjqnNs/om+a+BCoNStw5A47ChQtLtmzZpHv37nLp0iWPZqbMmTO7gh+lTYvOGjr9kGlzmL6/TunTp5dq1aq51jWA0Z9RnTp1XNuCgoKkRo0acvDgQY/yVKpUyfVYg1a9tjP4cW5LqHYQAIBU0QtMaxm0Bkdvau50/dChQ/d0jtdff93UQDgDHmetRHzndO6LbcKECTJmzBixA20OdNKalKeeekr69esn48ePN0GkNmE9++yzJjjV4MMZrLjTXB1vVRy6X0uvE9+1tZYQsFJStbf0ugQCj89zgB6ENpEsW7bM5JtoYu390mYWrclwLpp7Ygda+6bBhObwPP744/LII4/ImTNnknUOrV3TGiHNtXLSJjA9t5PWHjnzjpy0RkiToMuXL2/RqwEAIJXUAGlPpHTp0sm5c+c8tut6gQIFEn2uJuVqAKRNOO7NJs7n6Tn0xux+zipVqsR7rgwZMpjFbjQRWQMRTSpu1aqVKzE6uQYOHGh+FqVLl5ayZcuanmVXrlzxqHXSWibN9dFapqJFi5pEdW1m09omAABsVQOktQKak7JhwwbXNq2R0PVatWol+Dy9eY4dO9YkwrrnmihNvtUgyP2cmtOjNRSJndOOtMedBiuTJk2SihUrypIlS0xzYHJpwrnmDoWFhZn3WHOJ2rVr53GMBkgdOnQwxz322GMmqVq7vGtyNAAAtusFpt3g9cb57rvvmqRY7fL8ySefmBwgzdvRnl2aoOu8MevNWsf40W7R7km1Oj6NLs5j9IarXa41IBoxYoT8+uuvcuDAgXtqKrvfXmAAUidygFIOvcDgTcm5f/t8KozOnTvLhQsXTFCjScraTKU1O84kZh1zRnuGOc2dO9ck6P7jH//wOI+OI6RjyDjHnNGu188//7xpitFB9/ScD5InBAAAAofPa4D8ETVAgL1QA5RyqAGCN6WacYAAAAB8gQAIAADYDgEQAACwHQIgAABgOwRAAADAdgiAAACA7RAAAQAA2yEAAgAAtkMABAAAbIcACAAA2A4BEAAAsB0CIAAAYDuWBEA64zoAAEDABkCTJk2S5cuXu9Y7deokuXPnlsKFC8vevXutLh8AAIDvA6B58+ZJkSJFzON169aZ5bvvvpMWLVrI0KFDrS8hAACAxdIn9wkRERGuAGjlypWmBqhp06YSEhIiNWvWtLp8AAAAvq8BypUrl5w6dco8Xr16tTRp0sQ8djgcEh0dbX0JAQAAfF0D1L59e+nWrZuULl1aLl26ZJq+1J49e6RUqVJWlw8AAMD3AdD06dNNc5fWAk2ePFmyZs1qtp89e1ZefPFF60sIAADg6wAoKChIhgwZEmf7q6++alWZAAAA/CsAUkeOHJGNGzfK+fPnJSYmxmPfyJEjrSobACAFhAxblej+ExNbplhZAL8NgObPny/9+vWTPHnySIECBSRNmjSuffqYAAgAEha6MDTR/fvC9qVYWQA7S3YANG7cOBk/fry8/vrr3ikRAACAv3WD/+uvv6Rjx47eKQ0AAIA/BkAa/Kxdu9Y7pQEAAPDHJjAd62fEiBGybds2CQ0NNb3C3L388stWlg8AAMD3AdB7771nxv7ZtGmTWdxpEjQBEAAACLgA6Pjx494pCQAAgL/mALnT+b90AQAACPgAaNGiRSb/J1OmTGapVKmSLF682PrSAQAA+EMT2LRp00wSdP/+/aVOnTpm2+bNm6Vv375y8eJFpsQAAACBFwDNmjVL5s6dKz169HBta926tVSoUEFGjx5NAAQAAAKvCUxnfa9du3ac7bpN9wEAAARcAKTjAH3yySdxti9fvlxKly5tVbkAAAD8pwlszJgx0rlzZ/nxxx9dOUBbtmyRDRs2xBsYAQAApPoaoA4dOsjPP/9sZoNfsWKFWfTx9u3bpV27dt4pJQAAgC9rgFTVqlXlo48+srIcAAAA/hUARUZGSvbs2V2PE+M8DgAAIFUHQLly5TI9vPLlyyc5c+Y0c37FpiNC6/bo6GhvlBMAACBlA6Dvv/9eHnroIfN448aN1l0dAADAXwOgBg0auB4XL15cihQpEqcWSGuATp06ZX0JAQAAfN0LTAOgCxcuxNl++fJlsw8AACDgAiBnrk9s165dk4wZM1pVLgAAAN93gx80aJD5X4MfnQw1c+bMrn2a+KxjA1WpUsU7pQQAAPBFALRnzx5XDdC+ffskODjYtU8fV65cWYYMGWJl2QAAAHwbADl7f/Xq1UtmzpzJeD8AAMA+OUAzZsyQu3fvxpsEndQgiQAAAKkyAOrSpYssW7YsznadCFX3AQAABFwApMnOTzzxRJztDRs2NPsAAAACbjLUqKioeJvA7ty5Izdv3rSqXABsLnRhaKL794XtS7GyAAg8ya4BqlGjhrz33ntxts+bN8/MEg8AABBwNUDjxo2TJk2ayN69e6Vx48Zm24YNG2THjh2ydu1ab5QRAADAtzVAderUkfDwcDMfmCY+f/PNN1KqVCn59ddfpV69etaWDgAAwB9qgJSO+LxkyRLrSwMAAOCvAVBMTIwcPXpUzp8/bx67q1+/vlVlAwAA8I8AaNu2bdKtWzf5448/zLQY7nSeMJ0XDAAAIKACoL59+0q1atVk1apVUrBgwXhnhgcAAAioAOjIkSPy2WefmcRnAAAAW/QCq1mzpsn/AQAAsE0N0IABA2Tw4MESEREhoaGhEhQU5LG/UqVKVpYPAADA9wFQhw4dzP+9e/d2bdM8IE2IJgkaAAAEZAB0/Phx75QEAADAXwOgYsWKeackAAAA/hoALVq0KNH9PXr0eJDyAAAA+F8ANHDgQI/1O3fuyI0bNyQ4OFgyZ85MAAQAAAKvG/xff/3lsVy7dk0OHz4sdevWlY8//tg7pQQAAPBlABSf0qVLy8SJE+PUDt2LOXPmSEhIiGTMmNGMMbR9+/YEj/3tt99MLzQ9XnuczZgxI84xo0ePNvvcl7Jlyya7XAAAIHBZEgCp9OnTy5kzZ5L1nOXLl8ugQYNk1KhRsnv3bqlcubI0a9bMTLIaH21qK1GihAm2ChQokOB5K1SoIGfPnnUtmzdvTvbrAQAAgSvZOUBff/21x7qO/6NBxuzZs6VOnTrJOte0adOkT58+0qtXL7M+b948M8fYggULZNiwYXGOr169ullUfPvdg7HEAiQAAGBvyQ6A2rZt67GuTUx58+aVRo0aydSpU+/5PLdv35Zdu3bJ8OHDXdvSpk0rTZo0kfDwcHkQOl9ZoUKFTLNarVq1ZMKECVK0aNEEj4+KijKLU2Rk5ANdHwAABEAApAFB9uzZzeOYmBhLLnzx4kUzanT+/Pk9tuv6oUOH7vu8mkf04YcfSpkyZUzN1JgxY6RevXqyf/9+yZYtW7zP0QBJjwMAAPZwTzlAuXLlcuXlaE3PlStXxF+1aNFCOnbsaOYk03yib7/91pT3k08+SfA5Wgt19epV13Lq1KkULTMAAPDDGqCsWbPKpUuXJF++fPLDDz+YsX8eVJ48eSRdunRy7tw5j+26bmX+Ts6cOeWRRx5JdAb7DBkymAUAANjDPQVAmpfzxBNPSLly5cx6u3btzMCH8fn+++/v6cL6/KpVq8qGDRtceUXavKbr/fv3F6voOEXHjh2T7t27W3ZOAABggwDoo48+koULF5pAYtOmTaabuY76/KC0C3xYWJhUq1ZNatSoYcb1uX79uqtXmI4qXbhwYZOj40ycPnDggOvxn3/+Kb/88oupoSpVqpTZPmTIEGnVqpWZs0y75WsXe61p6tq16wOXFwAA2CgAypQpk/Tt29c83rlzp0yaNMk0LT2ozp07y4ULF2TkyJESEREhVapUkdWrV7sSo0+ePGl6hjlpQPPoo4+61qdMmWKWBg0amKY5dfr0aRPsaJOd9k7TEaq3bdtmHgMAANxXN/iNGzda+s5pc1dCTV7OoMZJR4DWcYcSs2zZMkvLBwAAAo9lI0EDAACkFgRAAADAdgiAAACA7SQ7ANLE5PjycHSb7gMAAAi4AKh48eKm51Zsly9fNvsAAAACLgDSmh6dADW+AQd18lEAAICA6QavgxYqDX5GjBjhMRCiTmr6888/m3F8AAAAAiYA2rNnj6sGaN++fR5TYejjypUrm1GYAQAAAiYAcg6AqNNUzJw5U7Jnz+7NcgEAAPjPSNAffPCBd0oCAADgrwFQo0aNEt1/r7PBAwAApJoASHN93N25c8fMyL5//34zszsAAEDABUDTp0+Pd/vo0aNNV3gAAADbTIXxzDPPyIIFC6w6HQAAgP8HQOHh4QyECAAAArMJrH379h7rOi7Q2bNnZefOnWaARAAAgIALgHLkyOGxnjZtWilTpoy8+eab0rRpUyvLBgAA4BWMAwQAAGwn2QGQkzZ5HTx40DwuX768VK1a1cpyAQAA+E8AdPr0aenatats2bJFcubMabZduXJFateuLcuWLZOHH37YG+UEAADwXS+w5557zgx+qLU/ly9fNos+jomJMfsAAAACrgZo06ZNsnXrVpP47KSPZ82aJfXq1bO6fAAAAL6vASpSpIipAYotOjpaChUqZFW5AAAA/CcAeuutt2TAgAEmCdpJHw8cOFCmTJlidfkAAAB83wTWs2dPuXHjhtSsWVPSp//fp9+9e9c87t27t1mcND8IAAAg1QdAM2bM8E5JAAAA/DUACgsL805JAAAA/HkgRO3yfvToUTl//rx57K5+/fpWlQ0AAL8XMmxVovtPTGyZYmWBFwOgbdu2Sbdu3eSPP/4wE6G6S5MmjekNBgAAEFABUN++faVatWqyatUqKViwoAl6AAAAAjoAOnLkiHz22WdSqlQp75QIAADA3wIg7f6u+T8EQIA9hS4MTXT/vrB9KVYWAEixAEgHQRw8eLBERERIaGioBAUFeeyvVKnSfRcGAADALwOgDh06mP/dBzzUPCBNiCYJGgAABGQAdPz4ce+UBAAAwF8DoGLFinmnJAAAy5CrBVgQAH399dfSokULk++jjxPTunXrezklAACAfwdAbdu2NUnP+fLlM48TQg4QAAAImADIfbqL2FNfAAAApDZpH+TJp0+fJiACAAD2CoDKly8vJ06csK40AAAA/h4AxZ4MFQAAIOADIAAAANsFQP/85z/loYcesq40AAAA/h4ADR8+XP766y+5e/eudSUCAADw9yawMmXKyJEjR6wpDQAAgD9NhdG+fft4t+vAhy+//LJky5bN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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "counts[:] = 0\n", "\n", "for _ in range(nsim):\n", " f = boolforge.random_function(n, bias=0.75, ALLOW_DEGENERATE_FUNCTIONS=True)\n", " g = boolforge.random_function(\n", " n, absolute_bias=0.5, USE_ABSOLUTE_BIAS=True, ALLOW_DEGENERATE_FUNCTIONS=True\n", " )\n", " h = boolforge.random_function(n, absolute_bias=0.5, ALLOW_DEGENERATE_FUNCTIONS=True)\n", "\n", " counts[0, f.get_hamming_weight()] += 1\n", " counts[1, g.get_hamming_weight()] += 1\n", " counts[2, h.get_hamming_weight()] += 1\n", "\n", "fig, ax = plt.subplots()\n", "for i, label in enumerate(labels):\n", " ax.bar(x - width + i * width, counts[i] / nsim, width=width, label=label)\n", "\n", "ax.legend(frameon=False)\n", "ax.set_xticks(x)\n", "ax.set_xlabel(\"Hamming weight\")\n", "ax.set_ylabel(f\"Proportion of {n}-input functions\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "cc3f9662", "metadata": { "lines_to_next_cell": 2 }, "source": [ "---\n", "## 7. Summary, interpretation, and outlook\n", "\n", "This tutorial demonstrated how BoolForge enables uniform random generation of\n", "Boolean functions under flexible structural and statistical constraints.\n", "\n", "Different constraints define fundamentally different ensembles, and being\n", "explicit about these choices is essential for a correct generation and interpretation of\n", "computational results.\n", "\n", "**Next steps:** In the next tutorial, these function-level ensembles will be\n", "used to study how Boolean function structure influences sensitivity and canalizing properties." ] }, { "cell_type": "markdown", "id": "9e8dd0ec", "metadata": {}, "source": [ "---\n", "## 8. Common pitfalls\n", "\n", "- `absolute_bias` has no effect unless `USE_ABSOLUTE_BIAS=True`.\n", "- `depth=0` without `EXACT_DEPTH=True` does not restrict the function space.\n", "- Constant functions are generated only if `ALLOW_DEGENERATE_FUNCTIONS=True`.\n", "- For larger $n$ (for sure whenever $n>10$), set `ALLOW_DEGENERATE_FUNCTIONS=True` to avoid expensive degeneracy tests. \n", "Almost all functions in many variables are non-degenerate." ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" }, "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 }