{ "cells": [ { "cell_type": "markdown", "id": "79e8b9e4", "metadata": {}, "source": [ "# Working with Boolean Networks\n", "\n", "While previous tutorials focused on individual Boolean functions, this tutorial\n", "introduces Boolean networks, which combine multiple Boolean functions into a\n", "dynamical system.\n", "\n", "## What you will learn\n", "In this tutorial you will learn how to:\n", "\n", "- create Boolean networks,\n", "- compute basic properties of the wiring diagram,\n", "- compute basic properties of Boolean networks.\n", "- transform Boolean networks through structural manipulations such as fixing \n", " node values or removing regulatory interactions.\n", "\n", "## Setup" ] }, { "cell_type": "code", "execution_count": 1, "id": "fbfeb884", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:08.405235Z", "iopub.status.busy": "2026-03-31T14:27:08.404933Z", "iopub.status.idle": "2026-03-31T14:27:09.161855Z", "shell.execute_reply": "2026-03-31T14:27:09.161612Z" } }, "outputs": [], "source": [ "import boolforge as bf\n", "import numpy as np" ] }, { "cell_type": "markdown", "id": "1391e3c6", "metadata": {}, "source": [ "## Boolean network theory\n", "\n", "A Boolean network $F = (f_1, \\ldots, f_N)$ is a dynamical system consisting of\n", "$N$ Boolean update functions. Each node can be in one of two states, 0 or 1,\n", "often interpreted as OFF/ON in biological contexts.\n", "\n", "Under *synchronous updating*, all nodes update simultaneously, yielding a\n", "deterministic state transition graph on $\\{0,1\\}^N$. \n", "Under *asynchronous updating*, only one node is updated at a time, yielding a\n", "stochastic transition graph. BoolForge implements both schemes.\n", "\n", "Real biological networks are typically sparsely connected. The *in-degree*\n", "of a node is the number of essential inputs of its update function. The\n", "*wiring diagram* encodes which nodes regulate which others.\n", "\n", "Despite their simplicity, Boolean networks can:\n", "\n", "- reproduce complex dynamics (oscillations, multistability),\n", "- predict gene knockout effects,\n", "- identify control strategies,\n", "- scale to genome-wide networks (1000s of nodes)." ] }, { "cell_type": "markdown", "id": "a00ad8f6", "metadata": {}, "source": [ "## Wiring diagrams\n", "\n", "We first construct wiring diagrams, which encode network structure independently\n", "of specific Boolean functions. Separating topology (encoded in BoolForge by `I`) \n", "from dynamics (`F`) allows:\n", "\n", "- studying structural properties independent of specific Boolean rules,\n", "- swapping different rule sets on the same topology,\n", "- efficient storage (sparse I, local F vs dense full truth table)." ] }, { "cell_type": "code", "execution_count": 2, "id": "bf60bf2d", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:09.163306Z", "iopub.status.busy": "2026-03-31T14:27:09.163182Z", "iopub.status.idle": "2026-03-31T14:27:09.450233Z", "shell.execute_reply": "2026-03-31T14:27:09.449999Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W.N: 3\n", "W.variables: ['x0' 'x1' 'x2']\n", "W.indegrees: [1 2 1]\n", "W.outdegrees: [1 2 1]\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Wiring diagram of a 3-node network\n", "I = [\n", " [1],\n", " [0, 2],\n", " [1],\n", "]\n", "\n", "W = bf.WiringDiagram(I=I)\n", "\n", "print(\"W.N:\", W.N)\n", "print(\"W.variables:\", W.variables)\n", "print(\"W.indegrees:\", W.indegrees)\n", "print(\"W.outdegrees:\", W.outdegrees)\n", "\n", "fig = W.plot(show=False);" ] }, { "cell_type": "markdown", "id": "fa721c0f", "metadata": { "lines_to_next_cell": 2 }, "source": [ "The wiring diagram above consists of $N=3$ variables, and \n", "uses default variable names $x_0, \\ldots, x_{N-1}$.\n", "The vectors `indegrees` and `outdegrees` describe the number of \n", "incoming and outgoing edges for each node." ] }, { "cell_type": "markdown", "id": "bfced456", "metadata": {}, "source": [ "### Example with constants and unequal degrees\n", "The next wiring diagram contains a constant node (source) $x_0$ and a node \n", "that is only regulated but does not regulate any nodes (sink) $x_2$." ] }, { "cell_type": "code", "execution_count": 3, "id": "92f1005b", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:09.451544Z", "iopub.status.busy": "2026-03-31T14:27:09.451419Z", "iopub.status.idle": "2026-03-31T14:27:09.495366Z", "shell.execute_reply": "2026-03-31T14:27:09.495099Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W.N: 3\n", "W.variables: ['x0' 'x1' 'x2']\n", "W.indegrees: [0 1 2]\n", "W.outdegrees: [2 1 0]\n" ] }, { "data": { "image/png": "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q0LwqBRu1D7277//ti5dulju3LkTZRwAgJSLYAEAHjp9+rTbgfq2225zbWsTU4cOHWz37t2u41NcW9ECABBX/GUBAA99+umnrr7isccei9fnaYM+zW6oc5QKvv33lbicAQMG2Jo1ayI39QMAICExYwEAHmrRooVrUauC7fjQ3hIFCxa0QoUK2S+//GJvvfWW6/wUGwURFWaPHz8+iFEDABAdMxYA4BHVNahTU2wdmLSpnva/UKep/fv3u+5RvlAh6vC0Z8+eOD2mHuu3335LkPEDAOAv5h2aAACJTp2ZtGt2bBvgXX/99S4QqAZD9RGDBg2KDBXyxRdfWNOmTeP0mHqsjz/+2NV2RN00DwCAYBAsAMAjai8rOXPmjPVYbXTXuHFjV+itImwf7e49YcIEt5t3XPge69SpUwQLAECCYikUAHgkQ4YM7q1qLOKyL8a5c+fs0KFDbgmVb6dutZBVAbj/PhRX4nss32MDAJBQCBYA4JESJUpYunTpbMOGDbEeq65Rr7/+uqunGDNmjB09etQ6depkb7zxhlWpUiXOj6nHypcvn+XIkSPI0QMAEIiuUADgoTp16ljFihVt7Nixlz1m4sSJruD6vffec8unVMh91113uYBRunRpd0zGjBntp59+ivXx2rZt65ZDaYdvAAASEsECADw0cOBAt5RpxYoVljVr1kR9rH379lmtWrXs1VdfdXtaAACQkFgKBQAe6t27t1vWpFmJxDZu3Dg3s9G9e/dEfywAQOpDsAAAD6nLU8eOHe3tt992e1Qkls2bN7tN8Xr16mW5c+dOtMcBAKReLIUCAI9pczvtL6Fai6+//toVdCcktZZt3ry522Dvjz/+oHAbAJAomLEAAI8VKVLEpkyZ4gq0+/fvH9lONiGcOXPGHnzwQduyZYtNnz6dUAEASDQECwBIBpo0aWKffPKJCxhaGnXs2LEEmQlR96iFCxfaV199ZdWqVUuQsQIAEBOCBQAkE127drXZs2fbsmXL7LrrrnM7al/N7IU20nv33XfthhtusB07dtj8+fPt9ttvT5QxAwDgQ40FACQzu3btsqefftp1ilLdxb333mvt27e34sWLx1qg/eWXX7pZj927d7tduV988cU478oNAEAwCBYAkEwtWbLERo0aZTNmzLDTp09b2bJlrWrVqi5sqFZCL99aMrV+/Xpbt26dbd++3W1+165dO7dPBUufAABJiWABAMlceHi4zZo1y/766y9btWqVbdiwwe3AnSZNGhcwqlSp4kJEvXr1rGXLlpYlSxavhwwASIUIFgAAAACCRvE2AAAAgKARLAAAAAAEjWABAAAAIGgECwAAAABBI1gAAAAACBrBAgAAAEDQCBYAAAAAgkawAAAAABA0ggUAAACAoBEsAAAAAASNYAEAAAAgaAQLAAAAAEEjWAAAAAAIGsECAAAAQNAIFgAAAACCRrAAAAAAEDSCBQAAAICgESwAAAAABI1gAQAAACBoBAsAAAAAQSNYAAAAAAgawQIAAABA0AgWAAAAAIJGsAAAAAAQNIIFAAAAgKARLAAAAAAEjWABAAAAIGgECwAAAABBI1gAAAAACBrBAgAAAEDQCBYAAAAAgkawAAAAABA0ggUAAACAoBEsAAAAAASNYAEAAAAgaAQLAAAAAEEjWAAAAAAIGsECAAAAQNAIFgAAAACCRrAAAAAAEDSCBQAAAICgESwAAAAABI1gAQAAACBoBAsAAAAAQSNYAAAAAAgawQIAAABA0AgWAAAAAIJGsAAAAAAQNIIFAAAAgKARLAAAAAAEjWABAAAAIGgECwAAAABBI1gAAAAACBrBAgAAAEDQCBYAAAAAgkawAAAAABA0ggUAAACAoBEsAAAAAASNYAEAAAAgaAQLAAAAAEEjWAAAAAAIGsECAAAAgAXr/wGLSJHbhJ7SQwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "I = [\n", " [],\n", " [0],\n", " [0, 1], \n", "]\n", "\n", "W = bf.WiringDiagram(I=I)\n", "\n", "print(\"W.N:\", W.N)\n", "print(\"W.variables:\", W.variables)\n", "print(\"W.indegrees:\", W.indegrees)\n", "print(\"W.outdegrees:\", W.outdegrees)\n", "\n", "fig = W.plot(show=False)" ] }, { "cell_type": "markdown", "id": "7d861432", "metadata": {}, "source": [ "This wiring diagram encodes a *feed-forward loop*, one of the most common *network motifs* in \n", "transcriptional networks. It can:\n", "\n", "- filter transient signals (coherent FFL with AND gate),\n", "- accelerate response (incoherent FFL),\n", "\n", "See @mangan2003structure for a detailed analysis.\n", "`BoolForge` enables the identification of all feed-forward loops:" ] }, { "cell_type": "code", "execution_count": 4, "id": "5ef90554", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:09.496500Z", "iopub.status.busy": "2026-03-31T14:27:09.496435Z", "iopub.status.idle": "2026-03-31T14:27:09.498108Z", "shell.execute_reply": "2026-03-31T14:27:09.497918Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W.get_ffls() {'FFLs': [[0, 1, 2]]}\n" ] } ], "source": [ "print(\"W.get_ffls()\", W.get_ffls())" ] }, { "cell_type": "markdown", "id": "5cab012e", "metadata": {}, "source": [ "This tells us that `W` contains one FFL, in which $x_0$ regulates both $x_1$ and $x_2$, \n", "while $x_2$ is also regulated by $x_1$.\n", "\n", "`BoolForge` can also identify all feedback loops. For this, we consider another wiring diagram:" ] }, { "cell_type": "code", "execution_count": 5, "id": "116a1f15", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:09.499086Z", "iopub.status.busy": "2026-03-31T14:27:09.499021Z", "iopub.status.idle": "2026-03-31T14:27:09.529607Z", "shell.execute_reply": "2026-03-31T14:27:09.529384Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W2.get_fbls() {'FBLs': [[0, 1, 2], [0, 1]]}\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "I2 = [\n", " [2,1],\n", " [0],\n", " [1],\n", "]\n", "\n", "W2 = bf.WiringDiagram(I=I2)\n", "fig = W2.plot(show=False)\n", "fig\n", "\n", "print(\"W2.get_fbls()\", W2.get_fbls())" ] }, { "cell_type": "markdown", "id": "915c7c30", "metadata": {}, "source": [ "The function `.get_fbls()` identifies all simple cycles in the wiring diagram. \n", "In this case, there exists a 2-cycle $x_0 \\leftrightarrow x_1$ and a 3-cycle $x_0 \\to x_1 \\to x_2 \\to x_0$." ] }, { "cell_type": "markdown", "id": "fa975b27", "metadata": {}, "source": [ "## Creating Boolean networks\n", "\n", "To create a Boolean network, we must specify:\n", "\n", "1. A wiring diagram `I`, describing who regulates whom.\n", "2. A list `F` of Boolean update functions (or truth tables), one per node." ] }, { "cell_type": "code", "execution_count": 6, "id": "2a151734", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:09.530657Z", "iopub.status.busy": "2026-03-31T14:27:09.530594Z", "iopub.status.idle": "2026-03-31T14:27:10.310507Z", "shell.execute_reply": "2026-03-31T14:27:10.310265Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " x0(t) x1(t) x2(t) x0(t+1) x1(t+1) x2(t+1)\n", "0 0 0 0 0 0 0\n", "1 0 0 1 0 1 0\n", "2 0 1 0 1 0 1\n", "3 0 1 1 1 1 1\n", "4 1 0 0 0 1 0\n", "5 1 0 1 0 1 0\n", "6 1 1 0 1 1 1\n", "7 1 1 1 1 1 1\n" ] } ], "source": [ "I = [\n", " [1],\n", " [0, 2],\n", " [1],\n", "]\n", "\n", "F = [\n", " [0, 1],\n", " [0, 1, 1, 1],\n", " [0, 1],\n", "]\n", "\n", "bn = bf.BooleanNetwork(F=F, I=I)\n", "\n", "print(bn.to_truth_table().to_string())" ] }, { "cell_type": "markdown", "id": "1fde9e86", "metadata": {}, "source": [ "The full truth table of a Boolean network has size $N \\times 2^N$ and therefore grows exponentially with the number of nodes. \n", "In practice, however, `BoolForge` never stores this object explicitly. \n", "Instead, a Boolean network is represented internally by its wiring diagram `I` and the list of update functions `F`, \n", "which is far more memory-efficient – especially for sparse networks with few regulators per node.\n", "\n", "When a Boolean network is constructed from `F` and `I`, \n", "`BoolForge` automatically performs a series of consistency checks to guard against common modeling errors. \n", "For example, it verifies that each update function has the correct length, \n", "namely $2^n$, where $n$ is the number of regulators of the corresponding node as specified in `I`. \n", "If any of these checks fail, an informative error is raised immediately, \n", "helping ensure that the resulting network is well-defined." ] }, { "cell_type": "markdown", "id": "30055984", "metadata": {}, "source": [ "### Creating networks from strings\n", "\n", "Alternatively, Boolean networks can be specified using a human-readable\n", "string representation, where each line defines the update rule of one node.\n", "This format closely mirrors the way Boolean models are written in the literature\n", "and is often more convenient than manually specifying wiring diagrams and\n", "truth tables.\n", "\n", "In the example below, each line has the form $x_i = f_i(\\text{regulators of } x_i),$\n", "where Boolean operators such as `AND`, `OR`, and `NOT` can be used to define\n", "the update functions." ] }, { "cell_type": "code", "execution_count": 7, "id": "71f78a20", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.311811Z", "iopub.status.busy": "2026-03-31T14:27:10.311673Z", "iopub.status.idle": "2026-03-31T14:27:10.314110Z", "shell.execute_reply": "2026-03-31T14:27:10.313925Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " x(t) y(t) z(t) x(t+1) y(t+1) z(t+1)\n", "0 0 0 0 0 0 0\n", "1 0 0 1 0 1 0\n", "2 0 1 0 1 0 1\n", "3 0 1 1 1 1 1\n", "4 1 0 0 0 1 0\n", "5 1 0 1 0 1 0\n", "6 1 1 0 1 1 1\n", "7 1 1 1 1 1 1\n" ] } ], "source": [ "string = \"\"\"\n", "x = y\n", "y = x OR z\n", "z = y\n", "\"\"\"\n", "\n", "bn_str = bf.BooleanNetwork.from_string(string, separator=\"=\")\n", "print(bn_str.to_truth_table().to_string())" ] }, { "cell_type": "markdown", "id": "bc5e418e", "metadata": {}, "source": [ "Here, the update rule `x = y` specifies that node `x` copies the state of `y`,\n", "while `y = x OR z` indicates that node `y` becomes activated (1) whenever `x`,\n", "or `z`, or both are active.\n", "\n", "From this symbolic description, `BoolForge` automatically:\n", "\n", "- extracts the wiring diagram,\n", "- determines the regulators of each node,\n", "- constructs the corresponding Boolean update functions.\n", "\n", "Internally, the string representation is converted into the same `(F, I)`\n", "representation used throughout the package. As a result, Boolean networks\n", "created from strings behave identically to those created explicitly from\n", "wiring diagrams and truth tables.\n", "\n", "This interface is particularly useful for loading Boolean network models from\n", "external sources, such as `.bnet` files, or for quickly prototyping models in\n", "an interactive setting." ] }, { "cell_type": "markdown", "id": "c003826f", "metadata": {}, "source": [ "### Interoperability with CANA\n", "\n", "`BoolForge` provides native interoperability with\n", "the [CANA package](https://www.github.com/CASCI-lab/CANA) for the analysis of\n", "Boolean functions and Boolean networks [@marcus2025cana].\n", "Existing `BoolForge` networks can be converted into `CANA` objects and back\n", "without loss of information.\n", "\n", "In the example below, we convert a `BoolForge` Boolean network into its `CANA`\n", "representation using `to_cana()`, and then reconstruct a new `BoolForge`\n", "Boolean network from that `CANA` object.\n", "\n", "The final assertion verifies that this round-trip conversion preserves:\n", "\n", "- the Boolean update functions,\n", "- the wiring diagram,\n", "- and the variable names.\n", "\n", "This guarantees that `BoolForge` and `CANA` can be used interchangeably within\n", "a workflow, allowing users to leverage `CANA`'s analytical tools while\n", "continuing to build and manipulate models using `BoolForge`." ] }, { "cell_type": "code", "execution_count": 8, "id": "3b522ee2", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.315171Z", "iopub.status.busy": "2026-03-31T14:27:10.315100Z", "iopub.status.idle": "2026-03-31T14:27:10.369724Z", "shell.execute_reply": "2026-03-31T14:27:10.369480Z" } }, "outputs": [], "source": [ "cana_bn = bn.to_cana()\n", "bn_from_cana = bf.BooleanNetwork.from_cana(cana_bn)\n", "\n", "assert (\n", " np.all([np.all(bn.F[i].f == bn_from_cana.F[i].f) for i in range(bn.N)])\n", " and np.all([np.all(bn.I[i] == bn_from_cana.I[i]) for i in range(bn.N)])\n", " and np.all(bn.variables == bn_from_cana.variables)\n", "), \"BooleanNetwork CANA conversion failed\"" ] }, { "cell_type": "markdown", "id": "97db423f", "metadata": {}, "source": [ "## Types of nodes in Boolean networks\n", "\n", "Nodes in a Boolean network can be classified as follows:\n", "\n", "- *Constant nodes*: \n", " Nodes with constant update functions (always 0 or always 1).\n", " These nodes act as parameters and they are eliminated at construction time \n", " by substituting their constant value into all dependent update functions.\n", "- *Identity nodes*: \n", " Nodes whose update function is the identity, i.e., $f(x_i) = x_i.$\n", " Their value is determined by the initial condition and remains constant over time.\n", " Identity nodes are retained as part of the Boolean network state. \n", " They may be viewed as nodes with a self-loop and no other incoming edges.\n", "- *Regulated nodes*: \n", " Nodes whose update functions depend on one or more other nodes." ] }, { "cell_type": "code", "execution_count": 9, "id": "2caae437", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.371032Z", "iopub.status.busy": "2026-03-31T14:27:10.370950Z", "iopub.status.idle": "2026-03-31T14:27:10.373629Z", "shell.execute_reply": "2026-03-31T14:27:10.373397Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bn.variables: ['x0' 'x1' 'x2']\n", "bn.constants: {'x3': 0}\n", "bn.I: [array([1, 2]), array([0]), array([2])]\n", "bn.F:\n", " F[0] = BooleanFunction(name='x0', f=[0, 0, 0, 1])\n", " F[1] = BooleanFunction(name='x1', f=[0, 1])\n", " F[2] = BooleanFunction(name='x2', f=[0, 1])\n" ] } ], "source": [ "F = [\n", " [0, 0, 0, 1], # regulated\n", " [0, 1, 1, 1], # regulated\n", " [0, 1], # identity\n", " [0], # constant\n", "]\n", "\n", "I = [\n", " [1, 2], # regulated\n", " [0, 3], # regulated\n", " [2], # identity\n", " [], # constant\n", "]\n", "\n", "bn = bf.BooleanNetwork(F, I)\n", "\n", "print(\"bn.variables:\", bn.variables)\n", "print(\"bn.constants:\", bn.constants)\n", "print(\"bn.I:\", bn.I)\n", "print(\"bn.F:\")\n", "for i, f in enumerate(bn.F):\n", " print(f\" F[{i}] = {f!r}\")" ] }, { "cell_type": "markdown", "id": "c72b83bd", "metadata": {}, "source": [ "The constant node is removed, and its value is propagated into downstream\n", "update functions.\n", "\n", "If we now change the value of the constant node from 0 to 1, the network is\n", "constructed in the same way, and the constant value 1 is substituted directly\n", "into all downstream update functions, before removal of the constant node.\n", "\n", "As a result, the Boolean update functions of downstream nodes may simplify,\n", "potentially reducing the number of regulators or changing the logical form\n", "of the function. This illustrates how constant nodes act as parameters whose\n", "values influence the effective dynamics of the network.\n", "\n", "Importantly, this simplification is performed symbolically at construction\n", "time and does not depend on the dynamical evolution of the network." ] }, { "cell_type": "code", "execution_count": 10, "id": "98123501", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.374826Z", "iopub.status.busy": "2026-03-31T14:27:10.374750Z", "iopub.status.idle": "2026-03-31T14:27:10.377118Z", "shell.execute_reply": "2026-03-31T14:27:10.376911Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bn.variables: ['x0' 'x1' 'x2']\n", "bn.constants: {'x3': 1}\n", "bn.I: [array([1, 2]), array([0]), array([2])]\n", "bn.F:\n", " F[0] = BooleanFunction(name='x0', f=[0, 0, 0, 1])\n", " F[1] = BooleanFunction(name='x1', f=[1, 1])\n", " F[2] = BooleanFunction(name='x2', f=[0, 1])\n" ] } ], "source": [ "F = [\n", " [0, 0, 0, 1],\n", " [0, 1, 1, 1],\n", " [0, 1],\n", " [1],\n", "]\n", "\n", "I = [\n", " [1, 2],\n", " [0, 3],\n", " [2],\n", " [],\n", "]\n", "\n", "bn = bf.BooleanNetwork(F, I)\n", "\n", "print(\"bn.variables:\", bn.variables)\n", "print(\"bn.constants:\", bn.constants)\n", "print(\"bn.I:\", bn.I)\n", "print(\"bn.F:\")\n", "for i, f in enumerate(bn.F):\n", " print(f\" F[{i}] = {f!r}\")" ] }, { "cell_type": "markdown", "id": "c009e1ff", "metadata": { "lines_to_next_cell": 2 }, "source": [ "Although $x_1$ becomes fixed at 1 after one update, it is not treated as a\n", "constant node. In `BoolForge`, constant nodes are identified by their update\n", "functions (always 0 or always 1), not by their long-term dynamical behavior.\n", "In other words, BoolForge distinguishes structural constants (defined by update rules)\n", "from dynamical constants (states that become fixed along trajectories).\n", "Since $x_1 = 0$ remains a valid initial condition, the node is retained as part\n", "of the network state." ] }, { "cell_type": "markdown", "id": "de04427a", "metadata": {}, "source": [ "## Boolean network properties\n", "\n", "The class `BooleanNetwork` inherits basic structural properties and methods\n", "from `WiringDiagram`. In particular, all graph-theoretic attributes of the\n", "wiring diagram -- such as the number of nodes, in-degrees, and out-degrees -- are\n", "directly accessible on a Boolean network object.\n", "\n", "Moreover, `BooleanNetwork` inherits visualization utilities from\n", "`WiringDiagram`, including methods for plotting the wiring diagram and its\n", "modular structure, using `.plot()`. This allows users to inspect the topology of a Boolean\n", "network independently of the specific update functions.\n", "\n", "Beyond these inherited features, `BooleanNetwork` provides a rich collection\n", "of additional methods for analyzing the dynamics, structure, and control\n", "properties of Boolean networks. These include functionality for:\n", "\n", "- computing fixed points and attractors,\n", "- analyzing transient dynamics and state transition graphs,\n", "- studying robustness and sensitivity to perturbations,\n", "- performing node and edge interventions.\n", "\n", "Many of these methods will be introduced and discussed in detail in the\n", "following tutorials. Here, we focus only on a few basic and commonly used\n", "properties." ] }, { "cell_type": "code", "execution_count": 11, "id": "7ae2cb16", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.378264Z", "iopub.status.busy": "2026-03-31T14:27:10.378199Z", "iopub.status.idle": "2026-03-31T14:27:10.445551Z", "shell.execute_reply": "2026-03-31T14:27:10.445265Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bn.N: 3\n", "bn.indegrees: [2 1 1]\n", "bn.outdegrees: [1 1 2]\n", "bn.variables: ['x0' 'x1' 'x2']\n" ] }, { "data": { "image/png": "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fvjhB1OuHTt2OOKj27dvO7Zs2fLY9999913zulavXm1LuRD/ERgQLYULF3bUqFEj0uO0wk+cOLGjdu3aLp23V69eplILq8KLirlz5zrKlCnjSJ48ueOpp55ytGvXznHmzJngn1evXt08T8hbp06dwj3f9evXHf3793fkzp3bkTRpUhMUa9Wq5di1a1fwMfp4/XlEz+G8TZ06Nfg4Da567hw5cphz58+f3/HRRx857t+/H63Xvm/fPvMcEyZMiNbjgcRRb2MAYsYVtNviwIEDpqsnPCtWrJB79+5Jhw4dXDrv0qVLzbhC5cqVo1027XfXsYvy5cvLhx9+KP7+/mZsYsuWLbJ7925Jly6dDB8+XAoXLmy6pEaPHi158+aV/Pnzh3vOXr16ybx58+S1116TYsWKmfEJ7do6dOiQlClTJszH6HN0797d8r2ZM2fKypUrTbePunnzplSvXl3Onj1rxlS0a0676YYNGyZ+fn4ybty4KL/+8+fPm/uMGTNG+bGAYXdkQvy0atUqR6JEicytUqVKjjfffNOxcuVKx507dyzHDRgwwFy97t69O9JzXrt2zRzbpEmTaJdLn9/X19dRokQJx61bt4K/v2zZMnPud955J/h7etXualdS2rRpTZdYREK3GELTVlCSJEkcXbt2Df7ee++950iVKpXjyJEjlmOHDh1q3tt///3XEVXakkmTJk2Y3XyAK5iVhGjR2UfaYtAZMXv37pWPP/5Y6tSpY2YmLVmyJPi469evm3sdJI1MVI4Nj85wunDhgvTu3dvMZnJq0KCBFClSxAxsR4e2Mv744w85d+5ctB6vV/E6g0unxk6ePDn4+z///LNUq1ZN0qdPL//991/wTQfDdSbXxo0bo/Q8//vf/2TNmjXy0UcfmTID0UFgQLRpV82CBQvkypUrsn37dtP9ERAQYCrAgwcPmmN0mqnS70cmKseG559//jH32k0UmgYG58+jSgOfdpvptNAKFSrIqFGj5MSJEy49VrvSdFqsVvT6foWctXT06FEzOypTpkyWm3OWlAY5V82ZM0fefvtt6datm7z66qvReJXAQ4wxIMaSJk1qgoTeChUqZPr39Up45MiRpjJ25jzo1XJkgSFbtmymAnY3WrHrlf3ChQtl1apV8sknn8iYMWNMRa9TXiMyePBg07rSK3nnlFwnnd6qra8333wzzMfq++kK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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "print(\"bn.N:\", bn.N)\n", "print(\"bn.indegrees:\", bn.indegrees)\n", "print(\"bn.outdegrees:\", bn.outdegrees)\n", "print(\"bn.variables:\", bn.variables)\n", "\n", "bn.plot();" ] }, { "cell_type": "markdown", "id": "65f2374a", "metadata": {}, "source": [ "Just like BooleanFunction objects, BooleanNetwork possesses a `.summary()` method,\n", "which prints a human-readable overview of basic properties.\n", "If more advanced properties have already been computed, e.g., attractors,\n", "this information is also displayed (or if the optional keyword `compute_all` is set to True, default False). " ] }, { "cell_type": "code", "execution_count": 12, "id": "8c21f545", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.446955Z", "iopub.status.busy": "2026-03-31T14:27:10.446840Z", "iopub.status.idle": "2026-03-31T14:27:10.492836Z", "shell.execute_reply": "2026-03-31T14:27:10.492573Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "BooleanNetwork\n", "--------------\n", "Number of nodes: 3\n", "Number of regulated nodes: 2\n", "Number of identity nodes: 1\n", "Number of constants (removed):1\n", "Average degree: 1.333\n", "Largest in-degree: 2\n", "Largest out-degree: 2\n", "Regulated nodes: ['x0', 'x1']\n", "Identity nodes (inputs): ['x2']\n", "Constants: {'x3': 1}\n", "\n", "BooleanNetwork\n", "--------------\n", "Number of nodes: 3\n", "Number of regulated nodes: 2\n", "Number of identity nodes: 1\n", "Number of constants (removed):1\n", "Average degree: 1.333\n", "Largest in-degree: 2\n", "Largest out-degree: 2\n", "Regulated nodes: ['x0', 'x1']\n", "Identity nodes (inputs): ['x2']\n", "Constants: {'x3': 1}\n", "Number of attractors: 2\n", "Largest basin size: 0.500\n", "Basin size entropy: 0.693\n", "Derrida value: 0.667\n", "Coherence: 0.667\n", "Fragility: 0.222\n" ] } ], "source": [ "print(bn.summary())\n", "print()\n", "print(bn.summary(compute_all=True)) #or simply print(bn.summary(True))" ] }, { "cell_type": "markdown", "id": "f2068c06", "metadata": {}, "source": [ "The more advanced properties displayed here are the subject of the next two tutorials.\n", "\n", "\n", "## Manipulation and control of Boolean networks\n", "Identity nodes can represent external inputs or environmental conditions. \n", "Fixing their values allows us to study the behavior of the network under specific contexts.\n", "BoolForge enables users to obtain a reduced network, in which the identity nodes \n", "are set to specific values." ] }, { "cell_type": "code", "execution_count": 13, "id": "237c6d2f", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.494156Z", "iopub.status.busy": "2026-03-31T14:27:10.494077Z", "iopub.status.idle": "2026-03-31T14:27:10.496357Z", "shell.execute_reply": "2026-03-31T14:27:10.496096Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cn.F:\n", " F[0] = BooleanFunction(name='x0', f=[0, 0])\n", " F[1] = BooleanFunction(name='x1', f=[1, 1])\n", "\n", "BooleanNetwork\n", "--------------\n", "Number of nodes: 2\n", "Number of regulated nodes: 2\n", "Number of constants (removed):2\n", "Average degree: 1.000\n", "Largest in-degree: 1\n", "Largest out-degree: 1\n", "Regulated nodes: ['x0', 'x1']\n", "Constants: {'x2': 0, 'x3': 1}\n" ] } ], "source": [ "cn = bn.get_network_with_fixed_identity_nodes(values_identity_nodes=[0])\n", "print(\"cn.F:\")\n", "for i, f in enumerate(cn.F):\n", " print(f\" F[{i}] = {f!r}\")\n", "print()\n", "print(cn.summary())" ] }, { "cell_type": "markdown", "id": "c2287d5d", "metadata": {}, "source": [ "Fixing identity nodes converts them into constant nodes, which are then eliminated \n", "via constant propagation. Only the identity nodes are removed from `cn`. \n", "Nodes that become dynamically constant after fixing identity nodes (e.g., \n", "$x_0$ and $x_1$) are retained, since their initial values may still vary. \n", "For example, $x_0(t=0) = 1$ or $x_1(t=0) = 0$ remain valid initial values, \n", "despite the fact that $x_0(t) = 0$ and $x_1(t) = 1$ at any time $t>0$.\n", "\n", "### Node controls\n", "Boolean network control is an active area of research (see e.g., \n", "@murrugarra2016identification or @borriello2021basis). \n", "For example, the knock-out of a certain gene can be simulated in a Boolean network\n", "by setting this gene to a constant value of zero. Likewise, overexpression can be \n", "modeled by setting it to a constant value of one. BoolForge enables users to implement\n", "node and edge controls of existing Boolean networks. This provides a simple framework \n", "for simulating interventions such as gene knock-outs or overexpression.\n", "\n", "To implement node controls, we need to specify which nodes should be controlled and\n", "the constant values that they should be set to. As an example, we consider a classical\n", "Boolean network model, the three-node repressilator [@elowitz2000synthetic]." ] }, { "cell_type": "code", "execution_count": 14, "id": "60ebb8db", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.497501Z", "iopub.status.busy": "2026-03-31T14:27:10.497431Z", "iopub.status.idle": "2026-03-31T14:27:10.567916Z", "shell.execute_reply": "2026-03-31T14:27:10.567640Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAANNFJREFUeJzt3Ql4VPW9//GvJEAg7Pu+yS4gCLLvhF32PQG1i3uttLbVq71tr9fe2seqbW3Vp9raFsK+hS2ssiNgkH1RBGQH2ZeEsCTzf77feyf/JEzIJCeTM5O8X88zBs+cOfObJXA+57d8H/B4PB4BAAAAAAeKOHkwAAAAACiCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggWAoPDAAw/Ib37zm1w9tl69evLkk0/meZsQOLNmzZIKFSrIjRs3pKC6e/eu/OIXv5DatWtLkSJFZPjw4RLqXn31VenQoYPbzQAQpAgWANL885//tBN8vW3cuPGe+z0ej50k6f2PPfaYK20Mdvv377eA9O233xbqNtxPSkqK/PrXv5YXX3xRSpUqlSEger9/eiJerlw5admypTz99NOydevW+x5z6dKl9rgaNWpIampqlvtdu3ZNfvvb30q7du2kbNmyUrx4calbt66MGzdOlixZkqev8x//+Ie8/fbbMnr0aPnXv/4lP/nJT7LcV9v873//207aNXCVLl1aGjduLI8//rhs2bLlnv3PnTsnP/vZz6Rp06ZSsmRJiYyMlLZt28qbb74pV65cuWf/+fPny8CBA6VSpUpSrFgxe5/Gjh0rn332WY5e0+TJk2XXrl2ycOHCHD0OQOEQ7nYDAASfiIgImTZtmnTt2jXD9nXr1snJkyftZAxZn9T/13/9l/Ts2dNOlAtrG+5n0aJF8tVXX1lgyKx169by8ssv25+vX78uBw4ckNmzZ8vHH39sJ+bvvvuuz2PGxsbaa9UwpSfLUVFR9+zzzTffSP/+/eXYsWMyYsQIO2nXYHPixAkLJhqW9eR+0qRJefI6tR01a9aU9957L9t9f/zjH8tf//pXGTZsmMTExEh4eLi9R/Hx8dKgQQPp2LFj2r5ffPGFDBo0yHp7Jk6caIFCJSQkyFtvvSXr16+XFStWpF0M+P73v28XDdq0aSM//elPpVq1anLmzBkLG3369JFNmzZJ586d/XpN+lht4x/+8AcZOnRort8bAAUTwQLAPfSkRU/m/vznP9sJjpeGDT2JuXDhghRUycnJdkVXr5gHmp706fOVKFFCQkFiYqJdGXfq008/lS5duthJd2a6TU+W0/v9738v0dHRdoLeqFEjee655+5pV1xcnPzud7+zY2vIyBwsdFiShgm90q8BWZ8/Pe1B0ZNx7U3JK9999531umRH2/TBBx/IU089JX/7298y3PfHP/5Rzp8/n/b/2huhryMsLEx27NhhPRbpaW+MhjCvd955x0KF9jRoKNNeHa/XX39dpkyZkuF33B/a0zFmzBg5cuSIhR4ASOMBgP/z6aefevSvhdmzZ3seeOABz9KlS9Puu3Xrlqd8+fKed955x1O3bl3P4MGDMzz2xo0bnp/+9KeeWrVqeYoVK+Zp3Lix5+233/akpqZm2C85OdkzefJkT6VKlTylSpXyDBkyxHPixAl73l//+tdp+z3xxBP2PJnpPpn/6tL9dH+vixcvel5++WVPixYtPJGRkZ7SpUt7BgwY4Nm5c2eGx61Zs8aONX36dM/rr7/uqVGjhr3uy5cvZ/ke6b6PPPKItV2Pq8/xxz/+McP7l/mmz+Ntp75vy5Yt87Rt29ZTvHhxz3vvvec5evSo7aePzyzz+6JOnjzp+f73v++pXr26vdf16tXzPPvss/YZZdcGX8fz9R56j7N27VrPc88956lcubKnXLlyaffrd6Nr166ekiVL2nsxaNAgz969ez3ZuXnzprX5N7/5jc82ZP5eeV2/ft1ToUIFT82aNe/5Tk2ZMsVTpEgRz5kzZzy///3vPWXKlLHnSW/atGn2et566y2PU9l9172fZ1afQWaff/653f/Pf/4z2+fW9uu+sbGx2e6blJRk71nTpk09d+/ezXb/27dv2+fSsGFD+27qY7t06eJZsWJFhv2uXLlivyfvvvtutscEULgwxwLAPXRISadOnWT69Olp23RIxtWrV2X8+PH37K/nqzosQq8oDxgwwK6MNmnSRH7+85/b0Iv0fvjDH9pV2H79+tmwjaJFi8rgwYPztP16JXXBggU2tEXbou3Ys2eP9OjRQ06fPn3P/v/93/9t4+t1zPr//M//WI+FLytXrpQJEyZI+fLl7Sq6tl+HG+lQEtW9e3cb0qJee+01uxqst2bNmqUdQ4e36DH69u0rf/rTn2zoT05o+9u3by8zZsyweQHaq6RDd/QqfFJSkl9tyInnn3/ehlb96le/som7So+nn5kOI9L34T//8z9tHx06l928ju3bt8vt27flkUceyVE79Ln0Sv2pU6fsudLTHopevXrZMB39fuoQKh1ulZ73/zP3huSUP9/1ypUr23ukvQm1atXK9jPQOR5Kewn1M7wfndugPVw6byM7Ok/q0qVL1tujPRzZ0Xk5OoRO38u//OUv1qNRp04d+fLLLzPsp3NTHnzwwbTvPQCkcTvZAAge3qvUX3zxhecvf/mLXZHXq55qzJgxnl69evm8srxgwQJ73JtvvpnheKNHj7Yrm9988439v/YY6H7PP/98hv2io6PztMdCe0VSUlIy7KNXkfUq7BtvvHFPj0WDBg3SXuf9vPTSS3Y1/H5Xf7W3J6ur09pOvU97LDK3zd8ei8cff9yuzutnlJn3ivn92pDTHgvtlUj/erXnQHsunnrqqQyPP3v2rKds2bL3bM/sk08+sePu2bMnRz0WSnt39LFxcXFp286dO+cJDw/3fPzxx2nbOnfu7Bk2bFiGx7Zp0yZDj0v63ofz58+n3a5evXrf9vv7XVc9evTwPPTQQx5/6Oeqx9VewREjRnj+8Ic/eA4cOHDPfnr/ww8/7Ncx//SnP9kx58+f79f+etz7vf/p9evXz9OsWTO/9gVQeNBjASDLcdQ3b96UxYsX2xVg/alXPn3Ria96RdR7pdxLJ+Hquaz2dnj3U5n30/HfeUknl3vnSOiY+YsXL9oVb72ynPnqq3riiSf8mueg4+V1PL/2XORW/fr1bQJxbujKQdoTM2TIEFvVKLP04+fzio77T3+1W1+7jvPXXheda+O96T66otGaNWvuezz9LJT2+uSUdwUp/T56ac+NftajRo1K26Zt0+/c5cuXM6wGlX4FKi+9Kq89DN5bVt/xnH7Xc0rnhmgvgX4/dFK19p5pD4dOrtZemvSvQ1eM8ofuq/zdX7/f+/btk0OHDmW7r35+BXmuFYDcIVgA8ElPsnQCrE7Ynjdvnp2gZzX8QlfZ0eUrM5/AeId+6P3en3oSqMMo0tMT/rykJ+Deib4aMnSJTX09u3fvtuFcmenJnL/DgnQJUF22U4e46Go7y5Yty1Hb/H0uX3QSr54stmjRQvJL5vZ6Tzp79+6d4YRcbzr5WScs++N/O09yxlvzIv33bOrUqTY0TAOLrvqkN139SIdb6dAiL32Mr5oZ+plqWNJb1apVs22Dv9/1nNLfixdeeMGGiukJu05G1++ZriyVfvhhmTJlMgSr+9F9lb/7v/HGGxYa9Tuuy/zq8C79ncnq8wtEkAUQ2lgVCkCW9OqtXrE+e/asneT4s8JNXsnqpMWfVXt0noSO+9cTf50/oXUB9MRNe0Z81Tjwd1WmKlWqyM6dO2X58uV2ZVpveqVZly3VOgX+8PVcTl5rXsnquTK31/v+6ZwBndOQWXYrDFWsWNF+am+ChrOc2Lt3r/1s2LBhWsjRpVeVhsjMdO6Fd0lbne+gn51e/U+/GpWeROvNu8xyMND3SOdx6E3n8Oj8GQ0sOhfD+zo0OGU1F8jLu2KUzi/ypzifzs85fPiwhRoNiZ988okF9I8++sjmRqWnn58GdgBIjx4LAFnSybJ6Qq4Fuu43RERPeHRSceYrowcPHky73/tTT0z15CU9ndDsa6iFr0Jf/lwRnjNnjk1A/fvf/25Xe3WiuPa++DpeTunJnA5F0uVB9XU888wzVvtAr5Sr3FzF9Q4Lyty+zK9VewX0KrT3BDsr92uDr/dVT1K1roE/vL1NGrL0Pc180xNhf052jx49KjmhvQ06REgLNHp7BzQ46OR/HQ6lvRPpby+99JJs2LBBjh8/bvt6CzrqY5zw97ueV7xD3ryfj373dIji3Llzs32sTqbXz1sXYfA3pGoI/973vmeP0foerVq1skndmennl9sFAQAUXAQLAFnSMekffvihnVjoCc396l7oiYuOEU9Pr3bqSa72dijvT13JKD1dJcrXCawOW0o/FMNb1Cs7OgY+81AbPdlMP1Y9N7zzA7w0dOmJl7p165b99NZ5yEmI0bCgV3+1sFl6Gl4yP59eedYVjrQYWmbe13y/Nuj7mvl5tHaCvyeeOj9E26u9Qnfu3Lnn/vQ1F3zROigazny1Pyt6Iq0rX+kKRzonwhucNCR069bNVsfSYXrpbzqMR3lXNtM5Q82bN7ceLF+VrP0dnuXvdz0ntEcw80pX3sC3evVq+9y9vTTPPvusVK9e3eZ0fP311/c8RoeiafVtpRW5X3nlFSsyqD99vT4dSrZt2zaf32/9/dfn9X63vfT3UkO1v0X1ABQeDIUCcF86sTk7Gjq0h0BP+nS50YcfftiGUuiQCh1+5L3KrUur6sRaPWHWkxM9MdETJ+/V/vS0p0FPhrTXRCfK6jKcGnJ02IqvCdjp6dVpHS+uV171OXQoiJ6EOi3mpcNB9ORW5xfoMB7tUXj//fftdXmv3uqfNdjoMqz6GnWOh+6vV/izO7YuX6s/9Sq1nvz7OnHUE3p9b3XpXB3mo8+rgUuDky4vqsPV7tcGPb6enOpkZ13ydteuXTa0y99hLRoq9HPQE31dMlY/J+1J0Z4BXbJXC89lPulOT4cbaQ/SqlWr7DPKTMOfnux6eyn0hFtfm55868m09hCprVu32vfmRz/6kc/n0eFO2j793PV7pD0bGko1GOmV/JEjR1oo0RCmz6nLuOpryG7pY3+/6zmh1ex1noh+RjpZW4eYaUDQUKSfjx7X+/loD4S+Dg04+jmnr7ytvxf6GF0q2ksDlk7I1kJ5OrFeQ5ceX99PXQhAQ8XmzZttXw1e2uOkx9OeCw1/2vuX+T3Wz05DilbgBoAM3F6WCkBwLjd7P76WBdVlSH/yk59YkbmiRYt6GjVq5LNAnhYu+/GPf+ypWLGiFa/LqkCe0sJcWoBOi5A1adLEM3XqVL+Xm9UCeVpArkSJElbkS4uQ6fKfesu83Kwuz+qPOXPm2DKbVapUsTbVqVPH88wzz1hhtvR06VNdwjYsLMxngTxfdLnbH/zgB7Zkqy7zO3bsWM93333n8305duyYLU+qRet0CV19rhdeeMEK5GXXBl2G95VXXrEChVrcrn///rZEalbLzWb1XdDj6WO1vREREZ4HH3zQ8+STT3oSEhKyfR/nzZtnS7MeP37c53K8etP7dWlfXa5Vl7DdunVrhn1ffPFF2+/w4cNZPo8We9N9du3alaG4my45rMvPamE//Rxr165ty8UuWrTI4w9/v+v+Ljd77do1WxpW308tuqfH1O9Ap06d7HPMfFx1+vRpa4MW59P3Xz9LLbr429/+1ueSud7vrha90+V59Xdj3LhxVgDRS5fQbd++vS3Lq783WlhPj6eF89LTx+kyxACQ2QP6n4xRAwCAwNGhRHp1XIcn6dAkhA7t6dCVwnReCz0WADIjWAAA8t3MmTPlueees+FHvupLIDhp9XVdAtc7LwMA0iNYAAAAAHCMVaEAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOESwAAAAAOEawAAAAAOAYwQIAAACAYwQLAAAAAI4RLAAAAAA4RrAAAAAA4BjBAgAAAIBjBAsAAAAAjhEsAAAAADhGsAAAAADgGMECAAAAgGMECwAAAACOhTs/BOCeO3fuyIYNG2Tv3r3ywAMPSOvWraVz584SFhbmdtMAAAAKFYIFQlJKSor8+c9/ljfffFMuXbokxYsXF4/HI7dv35bKlSvLG2+8IU8//bQUKUKnHAAAQH7grAsh5+rVq9KjRw95+eWXZdiwYbJ69Wo5ffq03ZYvXy59+/aV5557TgYMGCCJiYluNxcAAKBQeMCjl3mBEHHjxg3p37+/7Nu3T6ZPny4dO3b0ud+aNWvk8ccfl06dOsmiRYskIiIi39sKAABQmNBjgZDy4osvyu7du2XOnDlZhgrVq1cvCx46/+KVV17J1zYCAAAURvRYIGSsWrXKhjnp3IqJEyf69ZgPPvhAfvnLX8rWrVulffv2AW8jAABAYUWwQMjQHgr9usbHx9sKUP5O8u7Zs6fUqFFDVqxYEfA2AgAAFFYMhUJI2LZtm/U6vPTSS36HCqXLzv7oRz+SlStXysGDBwPaRgAAgMKMYIGQ8PHHH0udOnWkX79+OX7s8OHDbQnaTz75JCBtAwAAAMECIeKzzz6z5WNzU/hOa1xERUXZMQAAABAYBAsEvVOnTsmRI0ds6VhftDeie/fuduvTp4/s2bPH5/yMXbt2WQ0MAAAA5D2CBYKeLhmrsgoWZcuWlfXr19tN52C8/fbb9+zTuXNnSU1Nlc2bNwe8vQAAAIURwQJBLyEhQerWrStVqlTJdt/r169LmTJl7tneoEEDqVixoh0LAAAAeS88AMcE8pQOX9JQcL/7dRjUzZs35dKlS7Js2bJ79tGVpCpUqMBQKAAAgAAhWCDoJSYmSsmSJbO83zsUSsXFxckvfvELmT9//j376TH0WAAAAMh7DIVC0Lt7967fq0H179/fal74UrRoUbl9+3Yetw4AAACKYIGgpz0NycnJfu2roULnY/iSlJQkkZGRedw6AAAAKIZCIehlN4TJO8fC4/FIeHi4vPfeez73I1gAAAAEDsECQU97IP7973/bkCgNDpmdP38+22NoMDl58qQd6/Lly7aEbe/evaVUqVIBajUAAEDhwlAoBL1u3bpZMNi9e3euj6HLzGow0WN9+umnMmzYMKlatao8/vjjsnr1aklJScnTNgMAABQ2BAsEvXbt2klERIR8/vnnuT6GFsbTJWubNWsmL7zwgnz44YfSqlUrmTJlikRFRUm9evXktddek6+++ipP2w4AAFBYPODRgelAkOvVq5cUL15cpk+fnqvHDx482ArsLViwIMP2r7/+2oZZacA4fvy4bWvfvr088cQTMn78eKt9AQAAgOzRY4GQMHLkSFm1apWcOnUqx489dOiQ9XboMTJr3LixvPnmm3L06FH57LPPLFDs27fPejWqV68uo0aNkoULF8qdO3fy6JUAAAAUTPRYICRcu3ZNatasKU8//bT88pe/zNFjX331VSuYd+LECev1yM6NGzds/3/9618WNvRXpHLlyhIdHW1zMtq0aWOVvAEAAPD/ESwQMn72s5/JRx99JFu2bLGQ4Y/Dhw9Lly5d5PXXX5df/epXOX5OHR41depUCxk6bEq1aNHCejZiYmKsVwMAAAAEC4QQrVehk6/1NnPmzGyrcWuV7eHDh8u5c+dk7969Vg8jt/TXRIvvacCYMWOGLVlbpEgR6devn4UMXWWqRIkSuT4+AABAqCNYIKSsWLFCBg0aJGPHjpX333/fTu590aVlf/jDH8qyZctsOdmuXbvmWRtu3bolixcvtpARHx9vz1WmTBlrk4YM7SFhqBQAAChsCBYIOdOmTZOJEydKnz595N1335VatWpluF8nYk+ePNkmbM+dO1eGDh0asLZ89913tlKVhowdO3bYtgYNGthcDL3Vr18/YM8NAAAQTAgWCElLliyRZ555Ri5cuGBL0Xbs2FFSU1OtXsW6detsDsbf//53q66dX/bs2WNL1+qcjLNnz9q27t27W8AYM2aM9WoAAAAUVAQLhPSci48//thqU+gcCh1+1Lp1a5tXocOgIiMjXWmXDo1auXKlhQxtW3Jyss2/GDFihA2V0p6W7OaHAAAAhBqCBRBAV65ckdmzZ9tQqU2bNtm2GjVq2FAuDRnNmzd3u4kAAAB5gmAB5BNd+lZ7MfT27bff2ra2bdtawJgwYYJUqlTJ7SYCAADkGsECyGc6F2Tjxo3Wi6G9GdevX5eiRYvK4MGDbT6G/ixWrJjbzQQAAMgRggXgoqSkJJuHoSFD52Xor2PFihWtB0NDRrt27Vi6FgAAhASCBRAkTp06lVbl+8CBA7ZNiwHqUCmdk+FvtXEAAAA3ECyAIKO/ktu3b7eAoTUyLl68aL0WUVFRFjJ0dSknVcQBAAACgWABBLHbt2/L0qVLLWRo7Y47d+5IqVKlrC6Ghoxu3bplWX0cAAAgPxEsgBChxQBnzJhhISMhIcG21atXTyZNmmTzMRo2bOh2EwEAQCFGsABC0P79+23Z2ilTpsjp06dtW5cuXawXQ3szypUr53YTAQBAIUOwAEJYSkqKrF692kLGvHnz5ObNm1K8eHGrPq4ho2/fvhIeHu52MwEAQCFAsAAKiGvXrsmcOXMsZKxbt862VatWTWJiYixktGzZ0u0mAgCAAoxgARRAR48etWFSGjK04rdq3bq1BYzo6GipUqWK200EAAAFDMECKMD013vz5s024XvmzJnWq6FDowYOHGgTvocMGWJDpwAAAJwiWACFhM6/WLhwoYWM5cuXS2pqqpQvX17Gjx9vIaNDhw5U+QYAALlGsAAKoTNnzsi0adMsZOzZs8e2NWnSxAKGVvmuU6eO200EAAAhhmABFGL6679z506bixEbGyvnz5+3XotevXrZfIyRI0daQT4AAIDsECwAGK3qvWzZMuvFWLRokVX9joyMlFGjRlnI6NmzJ1W+AQBAlggWAO5x6dIlm+ytIWPr1q22rXbt2mlVvnXYFAAAQHoECwD39dVXX6VV+T5x4oRt04ne2osxbtw4qVChgttNBAAAQYBgAcAvuorU2rVrrRdj7ty5kpiYKMWKFZOhQ4daL8aAAQOkaNGibjcTAAC4hGABIMdu3Lhh4UJ7MtasWWOTwLXonhbf05ChxfhYuhYAgMKFYAHAkePHj9swKe3JOHTokG1r2bKlDZWKiYmRatWqud1EAACQDwgWAPKE/lWiE701YMyYMUOuXLliq0j179/fQsawYcMkIiLC7WYCAIAAIVgAyHPJycmyePFiCxnx8fGSkpIiZcuWlbFjx1rI6Ny5M0OlAAAoYAgWAALq3LlzMn36dAsZWoxPPfjggzYXQ2/16tVzu4kAACAPECwA5Jvdu3fbhO+pU6da4FA9evSwXozRo0dL6dKl3W4iAADIJYIFgHx39+5dWbFihfVixMXFya1bt6REiRIycuRICxm9e/eWsLAwt5sJAABygGABwFU6yXvWrFnWk7Fp0ybbVrNmTZk4caKFjGbNmrndRAAA4AeCBYCg8c0331jA0NuxY8ds26OPPmpzMSZMmCAVK1Z0u4kAACALBAsAQVnle8OGDTZUavbs2VaQT6t6P/bYYxYyBg0aZFW/AQBA8CBYAAhqiYmJsmDBAgsZq1atsnoZlSpVsh4MDRlt27Zl6VoAAIIAwQJAyDh58qTExsZayDhw4IBta968uc3F0DkZNWrUcLuJAAAUWgQLACFH/9pKSEiwuRjTpk2TS5cuWZXvqKgoCxnDhw+XkiVLut1MAAAKFYIFgJB2+/ZtWbJkifVi6E9dylbrYYwZM8ZCRteuXS10AACAwCJYACgwLly4kFble/v27batfv36Nhdj0qRJVvEbAAAEBsECQIG0b9++tCrfp0+ftm3ae6G9GNqbUbZsWbebCABAgUKwAFCgpaSk2GpSGjLmz58vN2/elIiICJuHoSFD52WEh4e73UwAAEIewQJAoXHt2jWri6EhY/369batevXqEhMTYyGjRYsWbjcRAICQRbAAUCgdOXJEpkyZYiFD/6weeeQRm48RHR0tlStXdruJAACEFIIFgEJN/wrctGmTTfieNWuW9Wro0Cit7q0hQ6t9Fy9e3O1mAgAQ9AgWAPB/dP5FXFychYwVK1ZIamqqVKhQQcaPH29DpR599FGqfAMAkAWCBQD4oCtJafE9DRl79+61bU2bNrVeDK3yXbt2bbebCABAUCFYAMB96F+RO3bssIChQUNrZWivRe/eva0XY+TIkRIZGel2MwEAcB3BAgD8dOfOHYmPj7eQsWjRIvt/DRWjR4+2kNGjRw+qfAMACi2CBQDkwsWLF2XmzJkWMrZt22bb6tataxW+dbhUo0aN3G4iAAD5imABAA4dPHjQlq3V5WtPnjxp2zp16mS9GGPHjpXy5cu73UQAAAKOYAEAeVjle+3atdaLMXfuXElKSrKlaocOHWq9GP3795eiRYu63UwAAAKCYAEAAXD9+nWZN2+ehYw1a9bYtipVqqRV+X744YfdbiIAAHmKYAEAAXbs2DGZOnWqhYxDhw7ZtlatWlnA0KBRtWpVt5sIAIBjBAsAyCf61+2WLVssYOjE7ytXrkhYWJgNkdKQoUOmIiIi3G4mAAC5QrAAABckJyfbkrUaMpYtW2bzM8qWLSvjxo2zkKGTv6nyDQAIJQQLAHDZuXPn0qp879q1y7bpcrU64VuXr9VlbAEACHYECwAIIhosdOna2NhYCxyqZ8+e1osxatQoKV26tNtNBADAJ4IFAAShu3fvyvLlyy1kxMXFya1bt6RkyZIycuRICxm9evWy+RkAAAQLggUABLnLly/LrFmzLGRs3rzZttWqVUsmTpxoIaNp06ZuNxEAAIIFAIQSXa5WA4bejh8/btvat29v8zHGjx8vFStWdLuJAIBCimABACEoNTVV1q9fbxO+58yZIzdu3LCq3kOGDLGQMWjQIKp8AwDyFcECAEJcYmKizJ8/30LG6tWrrV5GpUqVJDo62oZKtWnThqVrAQABR7AAgALkxIkTtqKUhoyDBw/atoceeiityneNGjXcbiIAoIAiWABAAaR/tX/xxRcWMKZPn24TwIsUKSJ9+/a1kDF8+HApUaKE280EABQgBAsAKOB0qdolS5ZYyFi6dKktZVumTBkZM2aMhYyuXbsyVAoA4BjBAgAKkfPnz1sPhoaML7/80rY1aNAgrcq3/hkAgNwgWABAIbV3715btnbq1Kly5swZ29atWzfrxRg9erSULVvW7SYCAEIIwQIACjkdGrVq1SoLGbq6VHJyskRERMiIESMsZERFRVHlGwCQLYIFACDN1atXZfbs2RYyNmzYYNuqV6+eVuVbV5gCAMAXggUAwKcjR47IlClTLGTon1Xbtm1tPsaECROkcuXKbjcRABBECBYAgPvSfyY2btxoE75nzZol169fl/DwcBk8eLD1YujPYsWKud1MAIDLCBYAAL8lJSVJXFychYyVK1dKamqqVKhQwXowtCfj0UcfZelaACikCBYAgFw5ffp0WpXvffv22bamTZtaL4bOyahVq5bbTQQA5COCBQDAEf1nRGti6FyMadOmyYULF6zXok+fPhYydHWpyMhIt5sJAAgwggUAIM/cvn1b4uPjLWQsWrRI7ty5I6VKlbK6GBoyunfvLkWKFHG7mQCAACBYAAAC4uLFizJjxgwLGdu2bbNtdevWtQrfOh+jUaNGbjcRAJCHCBYAgIA7cOCABQxdvvbUqVO2rXPnzhYwxo0bJ+XKlXO7iQAAhwgWAIB8k5KSImvWrLEJ3/PmzbNVpooXLy7Dhg2zoVL9+vWzpWwBAKGHYAEAcIXWw5g7d66FjLVr19q2qlWrSkxMjIWMVq1aud1EAEAOECwAAK779ttv06p8f/PNN7bt4YcftoARHR1tgQMAENwIFgCAoKH/JH3++efWizFz5ky5evWqhIWFyYABAyxkDBkyRCIiItxuJgDAB4IFACAoJScny8KFCy1kLF++3OZn6CTv8ePH26Tvjh07UuUbAIIIwQIAEPTOnj1rxfc0ZOzevdu2NW7c2AKGVvnWZWwBAO4iWAAAQsrOnTttLkZsbKx89913tq1Xr142VGrUqFFWkA8AkP8IFgCAkKRVvXWIlIaMuLg4q/pdsmRJCxcaMjRsUOUbAPIPwQIAEPIuX75sk711qNSWLVtsW+3atW2YlIaMJk2auN1EACjwCBYAgALl66+/Tqvyffz4cdvWoUMHm4+hE78rVKjgdhMBoEAiWAAACqTU1FRZt26d9WLMmTNHEhMTpVixYvLYY49ZL8bAgQOlaNGibjcTAAoMggUAoMC7ceOGzJ8/30LGZ599ZvUyKleubMX3tCejTZs2LF0LAA4RLAAAhYoOj5o6daqFDB02pVq0aGG9GDExMVK9enW3mwgAIYlgAQAolPSfv23btlnAmDFjhk0A11Wk+vXrZyFj2LBhUqJECbebCQAhg2ABACj0bt26JYsXL7aQER8fL3fv3pUyZcrI2LFjLWR06dKFoVIAkA2CBQAA6WjRvenTp1vI2LFjh21r0KCBzcXQW/369d1uIgAEJYIFAABZ2LNnjy1dq3Myzp49a9u6d+9uAWPMmDHWqwEA+F8ECwAAsqFDo1auXGkhY8GCBZKcnGzzL0aMGGFDpfr06SNhYWFuNxMAXEWwAAAgB65cuSKzZ8+2oVKbNm2ybTVq1Eir8t28eXO3mwgAriBYAACQS4cPH7ZeDL19++23tq1t27YWMCZMmCCVKlVyu4kAkG8IFgAA5EGV740bN1ovhvZmXL9+3ap6Dx482OZj6E+t+g0ABRnBAgCAPJSUlGTzMDRk6LwM/We2YsWK1oOhIaNdu3YsXQugQCJYAAAQIKdOnUqr8n3gwAHb1qxZMxsqpXMyatas6XYTASDPECwAAAgw/ad2+/btFjC0RsbFixet1yIqKspCxvDhwyUyMtLtZgKAIwQLAADy0e3bt2Xp0qUWMpYsWSJ37tyRUqVKWV0MDRndunWTIkWKuN1MAMgxggUAAC65cOGCzJgxw0JGQkKCbatXr55MmjTJ5mM0bNjQ7SYCgN8IFgAABIH9+/fbsrVTpkyR06dP27bOnTtbL8bYsWOlXLlybjcRAO6LYAEAQBBJSUmR1atXW8iYN2+e3Lx5U4oXL27zMLQXo1+/fhIeHu52MwHgHgQLAACC1LVr12TOnDk2VGr9+vW2rVq1ahITE2Mho1WrVm43EQDSECwAAAgBR48etWFS2pOhFb9V69atbahUdHS0VKlSxe0mAijkCBYAAIQQ/Wd78+bN1osxc+ZM69UICwuTgQMHWsgYMmSIDZ0CgPxGsAAAIETp/Iu4uDjrxVi+fLmkpqZK+fLlZdy4cRYyOnToQJVvAPmGYAEAQAFw5swZiY2NtZ6MvXv32rbGjRvbXAxdvrZOnTpuNxFAAUewAACgANF/1nfu3GkBY9q0aXL+/HnrtejVq5f1YowcOdIK8gFAXiNYAABQQGlV72XLllnIWLRokVX9joyMlFGjRlnI6NmzJ1W+AeQZggUAAIXApUuXbLK3hoytW7fattq1a6dV+W7SpInbTQQQ4ggWAAAUMgcPHrSla/V24sQJ26YTvbUXQyd+V6hQwe0mAghBBAsAAAopXUVqzZo11osxd+5cSUpKkmLFisnQoUOtF2PAgAFStGhRt5sJIEQQLAAAgNy4ccPChYYMDRuqcuXKVnxPezK0GB9L1wK4H4IFAADI4NixYzJ16lQLGYcOHbJtLVu2tF6MmJgYqV69uttNBBCECBYAAMAnPUXQid4aMGbMmCFXrlyxVaT69+9vvRg6ZKpEiRJuNxNAkCBYAACAbCUnJ9uStVrlOz4+XlJSUqRs2bIyduxYCxmdO3dmqBRQyBEsAABAjpw7d86K72nI0GJ86sEHH7ShUnqrV6+e200E4AKCBQAAyLXdu3fbUKnY2FgLHKpHjx4WMEaPHi1lypRxu4kA8gnBAgAAOHb37l1ZsWKFhYy4uDi5deuWzb8YOXKkhYw+ffpIWFiY280EEEAECwAAkKcuX74ss2fPtpCxefNm21azZk2ZOHGihYzmzZu73UQAAUCwAAAAAaPL1WqFb52PocvYqnbt2tmE7wkTJkjFihXdbiKAPEKwAAAA+VLle/369daLMWfOHCvIp1W9Bw8ebCFj0KBBVvUbQOgiWAAAgHyVmJgo8+fPt5CxevVqq5ehPRfag6Eho23btixdC4QgggUAAHDNyZMn06p8Hzx40LbpHAwNGFrlW+dmAAgNBAsAAOA6PR1JSEiwgDF9+nS5dOmSVfmOioqykDF8+HApWbKk280EcB8ECwAAEFR0qdolS5bYhG/9qUvZli5dWsaMGWMho2vXrhY6AAQXggUAAAha58+ftx4MDRnbt2+3bVrZW5etnTRpkjRs2NDtJgL4PwQLAAAQEvbu3WsBQ+dknDlzxrZ16dLFejHGjh0rZcuWdbuJQKFGsAAAACFFh0bpalI6H0NXl0pOTpaIiAgZNmyYhYy+fftKeHi4280ECh2CBQAACFlXr161uhgaMjZs2GDbqlWrZitKacho2bKl200ECg2CBQAAKBCOHDmSVuVb/6zatGmTVuW7SpUqbjcRKNAIFgAAoEDRU5uNGzdaL8asWbPk+vXrNjRq4MCBFjIee+wxKV68uOv1OxYuXCg7d+609rZo0cKW1K1bt66r7QKcIFgAAIACKykpSeLi4ixkrFy5UlJTU6V8+fIyfvx4Cxnt27fP1yrf165dk1dffVU+/PBDCzsPPfSQPf/+/fvl9u3b8r3vfU/eeecdayMQaggWAACgUDh9+rTExsZayNi3b59ta9KkSdrStbVr1w7o8586dUp69OghZ8+elddee02io6PTVrLSwKFzRd544w0pU6aMrFu3Tho0aBDQ9gB5jWABAAAKFT312bFjhwWMadOmyYULF6zXoHfv3hYyRo4cKaVKlcrzehzdunWTxMRE60GpX79+lkOkdEiU9qzocK6aNWvmaTuAQCJYAACAQkuHHy1btsxCxqJFi+TOnTsSGRkpo0ePtpDRs2fPLKt8a4Vwf+Zq6KmWhoXNmzfbc2XXE6HhYsCAAdKsWTMbvpWfQ7UAJwgWAAAAInLx4kWZOXOmhYxt27bZtjp16tgwKQ0ZjRs3zjCsqVWrVjYR/B//+IeEhYVledwFCxbIiBEj7LhDhgzxqy1r1qyRUaNG2QpX+vxAKCBYAAAAZHLgwAE7qdflazVEqI4dO9qE73HjxslHH31k8yTUs88+Kx988IHPngU9zWrbtq3Nm5g3b16Oeh80zHz11Vdy8ODBLHtNgGBCsAAAAMhCSkqK9R5ob4MGA11lqmjRojYE6saNG2n76UpPv/vd7+55/KZNm6Rr16627G1UVFSOnnvLli0yaNAgiY+Pt6FRQLAjWAAAAPhB62HMnTtX3n//ffnyyy/vuV+DhQaM9J566ilZtWqVJCQk5LjXQU/RunfvbjUuZsyY4bj9QKDRrwYAAOCH0qVLy5NPPmlDonz5j//4D5k8eXKGbbpsrPZU5GYokw6b0sfqMbgOjFBAsAAAAMgBHdaUFa2m7aX1Kg4dOpRlEFHTp0+XqlWrypUrV3ze37lzZzvO4cOHHbYaCLzwfHgOAACAAkMnVR89elRq1aqV4VajRg2pV69e2n4bNmywn506dcryWPPnz5c2bdrI4sWLZeLEiffc760Mvn79emnYsGGAXhGQNwgWAAAAOfDOO+/4td/u3bstbFSvXt3n/ZcvX7aeiL/+9a/y9ttv+wwWWplbA4UeCwh2DIUCAAAIAF01SpeZzYoW5Bs4cKB06NBBjhw5YnU0fNFjpF+BCghWBAsAAIAASExMlJIlS953GJRW5NahToMHD7ag4YseQ48FBDuGQgEAAARAampqlgXxzp8/L1u3bpUf/OAH9v937tyRRo0a2apTmekx9FhAsKPHAgAAIAAiIyPl5s2bPu/T3gkNEbt27bLb/v375fjx43Lu3Ll79tVj6LGAYEewAAAACAANA1nNjdBhUDr8Kb3+/ftnWK7WS4dBESwQChgKBQAAEABNmzaVEydO2OpP5cuXz3Cfr/kUb7311j3bkpKSrBbG888/H9C2AnmBHgsAAIAA6Natm1XM1rkUubV9+3abf6HHAoIdwQIAACAAtFieFs7bvHlzro/x+eefS7ly5aRFixZ52jYgEAgWAAAAAaCrOXXv3l3Wrl1rPRe5oY/t2rWrFCnCKRuCH99SAACAAJkwYYLs3bvXhjTllK4UtWXLFomOjg5I24C89oAntxEaAAAA95WSkiKNGzeW1q1byyeffJKjx06ePFlWrFghx44dk2LFigWsjUBeoccCAAAgQMLCwuSVV16RefPmWe+Dv/bs2SNTp06Vl19+mVCBkEGPBQAAQIB7Lbp06SIXLlywHojMS89mdu3aNRk0aJCFkoSEBIIFQgY9FgAAAAGkAWHKlCly9epVGT16tAWHrGgxPJ2XcerUKYmNjSVUIKQQLAAAAAKsUaNGsnLlSjl69KjVpNA/px80on9ev3699OjRQ3bv3i3x8fHSsmVLV9sM5BRDoQAAAPLJkSNH5Omnn5bVq1dbjYsOHTrYUrJaRO/48eM2ZEoneWvVbiDUECwAAADykZ56aX2KBQsWyI4dO+z/tXdi+PDhEhUVRc0KhCyCBQAAAADHiMQAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAMcIFgAAAAAcI1gAAAAAcIxgAQAAAMAxggUAAAAAxwgWAAAAABwjWAAAAABwjGABAAAAwDGCBQAAAADHCBYAAAAAHCNYAAAAAHCMYAEAAADAMYIFAAAAAHHq/wGX7e0clYRkfgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "cn.F:\n", " F[0] = BooleanFunction(name='A', f=[1, 0])\n", " F[1] = BooleanFunction(name='B', f=[1, 1])\n", "cn.constants: {'C': 0}\n" ] } ], "source": [ "string = \"\"\"\n", "A = not B\n", "B = not C\n", "C = not A\n", "\"\"\"\n", "\n", "bn = bf.BooleanNetwork.from_string(string, separator=\"=\")\n", "bn.plot();\n", "cn = bn.get_network_with_node_controls(indices_controlled_nodes=[2],\n", " values_controlled_nodes=[0])\n", "cn.plot();\n", "print(\"cn.F:\")\n", "for i, f in enumerate(cn.F):\n", " print(f\" F[{i}] = {f!r}\")\n", "print(\"cn.constants:\", cn.constants)" ] }, { "cell_type": "markdown", "id": "4f514b0c", "metadata": {}, "source": [ "Setting $C = 0$ removes $C$ from the reduced network `cn` (it becomes a constant).\n", "Moreover, since $B = \\neg C$, we get $B = 1$ always, while the update rule for $A$ \n", "is not changed.\n", "\n", "### Edge controls\n", "Similarly, we can implement edge controls. Edge control removes the influence \n", "of a source node on a target node by fixing the source to a specified value \n", "within the target's update function. The resulting function is then simplified, \n", "and the corresponding edge is removed. As an example, we consider \n", "a more connected Boolean network with different types of update rules." ] }, { "cell_type": "code", "execution_count": 15, "id": "5df154a4", "metadata": { "execution": { "iopub.execute_input": "2026-03-31T14:27:10.569269Z", "iopub.status.busy": "2026-03-31T14:27:10.569174Z", "iopub.status.idle": "2026-03-31T14:27:10.572134Z", "shell.execute_reply": "2026-03-31T14:27:10.571860Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bn.I: [array([1, 2]), array([0, 2]), array([0, 1])]\n", "bn.F:\n", " F[0] = BooleanFunction(name='A', f=[0, 0, 0, 1])\n", " F[1] = BooleanFunction(name='B', f=[0, 1, 1, 1])\n", " F[2] = BooleanFunction(name='C', f=[0, 0, 1, 0])\n", "\n", "cn.I: [array([2]), array([0, 2]), array([0, 1])]\n", "cn.F:\n", " F[0] = BooleanFunction(name='A', f=[0, 0])\n", " F[1] = BooleanFunction(name='B', f=[0, 1, 1, 1])\n", " F[2] = BooleanFunction(name='C', f=[0, 0, 1, 0])\n" ] } ], "source": [ "string = \"\"\"\n", "A = B and C\n", "B = A or C\n", "C = A and not B\n", "\"\"\"\n", "bn = bf.BooleanNetwork.from_string(string, separator=\"=\")\n", "print(\"bn.I:\", bn.I)\n", "print(\"bn.F:\")\n", "for i, f in enumerate(bn.F):\n", " print(f\" F[{i}] = {f!r}\")\n", "print()\n", "\n", "cn = bn.get_network_with_edge_controls(control_targets=[0],\n", " control_sources=[1],\n", " values_edge_controls=[0])\n", "print(\"cn.I:\", cn.I)\n", "print(\"cn.F:\")\n", "for i, f in enumerate(cn.F):\n", " print(f\" F[{i}] = {f!r}\")" ] }, { "cell_type": "markdown", "id": "9af97915", "metadata": {}, "source": [ "By setting $B=0$ in the regulation of $A$, we remove $B$'s influence on $A$.\n", "Moreover, since $A = B \\wedge C$, we now have $A=0$ always.\n", "\n", "## Outlook\n", "\n", "In the remaining tutorials, we build on this foundation to study the dynamical\n", "behavior of Boolean networks, including attractors, basins of attraction,\n", "and stability under perturbations." ] } ], "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 }