From ddbda0b560c7d4b1316be44e178d3f696322dfd0 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 3 Jun 2024 15:39:43 -0400 Subject: [PATCH 01/14] cleaned imports in tests and some other files --- cana/boolean_network.py | 8 +- cana/canalization/boolean_canalization.py | 2 +- cana/control/sc.py | 4 +- tests/helpers/helper.py | 2 +- tests/test_boolean_canalization.py | 7 +- tests/test_boolean_network.py | 2 - tests/test_boolean_node.py | 3 +- tests/test_two_symbol_symmetry.py | 3 - ...lization - BioModels - Look Up Table.ipynb | 6 +- ...Canalization - BioModels - Schematas.ipynb | 22 +- tutorials/Canalization - BioModels.ipynb | 978 +-- tutorials/Canalization - Marques-Pita.ipynb | 175 +- tutorials/Canalization - Node Schematas.ipynb | 1005 +-- ...ntrol - BioModels - Driver Variables.ipynb | 820 +- .../Control - State Transition Graph.ipynb | 34 +- tutorials/Control - Thaliana.ipynb | 62 +- ...ics Canalization Map - Breast Cancer.ipynb | 6773 ++++++++--------- tutorials/Dynamics Canalization Map.ipynb | 1884 ++--- .../PNAS 2021 - Arabidopsis thaliana.ipynb | 272 +- tutorials/PNAS 2021 - ER+ Breast Cancer.ipynb | 10 +- 20 files changed, 5072 insertions(+), 7000 deletions(-) diff --git a/cana/boolean_network.py b/cana/boolean_network.py index 3df7f83..00669da 100644 --- a/cana/boolean_network.py +++ b/cana/boolean_network.py @@ -1191,7 +1191,7 @@ def pinned_step(self, initial, pinned_binstate, pinned_var): return "".join( [ str(node.step("".join(initial[j] for j in self.logic[i]["in"]))) - if not (i in pinned_var) + if i not in pinned_var else initial[i] for i, node in enumerate(self.nodes, start=0) ] @@ -1582,7 +1582,7 @@ def inv_eff_weight_func(pathlength): Gstr_shortest_dist, Gstr_shortest_paths = nx.single_source_dijkstra( Gstr, source, target=None, cutoff=n_steps ) - Gstr_shortest_dist = {n: int(l) for n, l in Gstr_shortest_dist.items()} + Gstr_shortest_dist = {n: int(m) for n, m in Gstr_shortest_dist.items()} # in the effective graph, calcluate the dijkstra shortest paths from the source to all targets that are shorter than the cufoff # where the edge weight is given by the effective weight function @@ -1593,14 +1593,14 @@ def inv_eff_weight_func(pathlength): for itar, target in enumerate(target_set): # we dont need to worry about a path to iteself (source==target) # and if the target doesnt appear in the shortest path dict, then no path exists that is less than the cutoff - if target != source and not Gstr_shortest_dist.get(target, None) is None: + if target != source and Gstr_shortest_dist.get(target, None) is not None: # the light cone is at least as big as the number of edges in the structural shorest path impact_matrix[ 0, list(range(Gstr_shortest_dist[target], n_steps + 1)), itar ] = Gstr_shortest_dist[target] # if the path exists, then the number of edges (timesteps) is one less than the number of nodes - if not Geff_shortest_paths.get(target, None) is None: + if Geff_shortest_paths.get(target, None) is not None: eff_path_steps = len(Geff_shortest_paths[target]) - 1 else: # or the path doesnt exist diff --git a/cana/canalization/boolean_canalization.py b/cana/canalization/boolean_canalization.py index 5b5f6b4..3711a0d 100644 --- a/cana/canalization/boolean_canalization.py +++ b/cana/canalization/boolean_canalization.py @@ -296,7 +296,7 @@ def _expand_ts_logic(two_symbols, permut_indexes): _implicant = np.copy(implicant) _implicant[idxs] = vals # Insert to list of logics if not already there - if not (_implicant.tolist() in logics): + if _implicant.tolist() not in logics: logics.append(_implicant.tolist()) Q.append(_implicant.tolist()) return logics diff --git a/cana/control/sc.py b/cana/control/sc.py index d8e719e..a3de95e 100644 --- a/cana/control/sc.py +++ b/cana/control/sc.py @@ -210,7 +210,7 @@ def _trim_unnecessary_edges(matching_digraph): def _enumerate_maximum_matchings_iter(G, U, V, M, D, matchings_list): """ """ - if len(G) > 0 and not (D is None): + if len(G) > 0 and D is not None: # find the cycles in the matching digraph cycles = [c for c in nx.simple_cycles(D)] @@ -246,7 +246,7 @@ def _enumerate_maximum_matchings_iter(G, U, V, M, D, matchings_list): elif len(G) > 0: path = _find_path_length_two(G, V, M) - if not (path is None): + if path is not None: # swap edges in the path e, Mprime = _swap_edges_in_path(path, M) # this creates a new maximum matching, see if we already have it or add it diff --git a/tests/helpers/helper.py b/tests/helpers/helper.py index e57a796..396e0dc 100644 --- a/tests/helpers/helper.py +++ b/tests/helpers/helper.py @@ -42,7 +42,7 @@ def expandTs(ts): obsSet = set() # for each schema and its symmetries for t, g in zip(tss, perms): - if type(t) == str: + if isinstance(t, str): t = list(t) # for each subset of indices that can be permuted x = [] diff --git a/tests/test_boolean_canalization.py b/tests/test_boolean_canalization.py index 4fb4083..e374b20 100644 --- a/tests/test_boolean_canalization.py +++ b/tests/test_boolean_canalization.py @@ -4,10 +4,11 @@ # These tests were hand calculated by Luis M. Rocha and implemented by Rion B. Correia. # Checks were made with the online tool: http://www.mathematik.uni-marburg.de/~thormae/lectures/ti1/code/qmc/ # -from cana.canalization.boolean_canalization import * -from cana.canalization.cboolean_canalization import * +# from cana.canalization.boolean_canalization import * +from cana.canalization.cboolean_canalization import find_implicants_qm from cana.cutils import outputs_to_binstates_of_given_type -from helper import * +from helpers.helper import reorderTwoSymbolOutput, randNode, enumerateImplicants, expandPi +from cana.canalization.boolean_canalization import find_two_symbols_v2 def test_AND(): """Test Canalization - AND (k=2, outputs=[0,0,0,1])""" diff --git a/tests/test_boolean_network.py b/tests/test_boolean_network.py index 90f2b94..8590804 100644 --- a/tests/test_boolean_network.py +++ b/tests/test_boolean_network.py @@ -1,5 +1,3 @@ -from cana.boolean_network import BooleanNetwork -import networkx as nx from cana.datasets.bio import THALIANA def test_EG_weight_THALIANA(): diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index 5b9a1ec..d426881 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -4,9 +4,8 @@ # These tests were manually calculated by Luis M. Rocha and implemented by Rion B. Correia. # from cana.datasets.bools import CONTRADICTION, AND, OR, XOR, COPYx1, RULE90, RULE110 -from cana.utils import * +from cana.utils import isclose from cana.boolean_node import BooleanNode -import numpy as np # diff --git a/tests/test_two_symbol_symmetry.py b/tests/test_two_symbol_symmetry.py index 795f02a..05c83af 100644 --- a/tests/test_two_symbol_symmetry.py +++ b/tests/test_two_symbol_symmetry.py @@ -3,9 +3,6 @@ import helpers.helper as helper from cana.boolean_node import BooleanNode -from cana.canalization.boolean_canalization import * # WARNING: some functions here differ from the file below! -from cana.canalization.cboolean_canalization import * -from cana.cutils import outputs_to_binstates_of_given_type # WARNING: ignoring detection of same-symbol symmetry for now. Complicating issues. diff --git a/tutorials/Canalization - BioModels - Look Up Table.ipynb b/tutorials/Canalization - BioModels - Look Up Table.ipynb index 7c76fbe..7e27ecb 100644 --- a/tutorials/Canalization - BioModels - Look Up Table.ipynb +++ b/tutorials/Canalization - BioModels - Look Up Table.ipynb @@ -27,7 +27,7 @@ "source": [ "import matplotlib.pyplot as plt\n", "from matplotlib.text import Text\n", - "from matplotlib.patches import Circle, Rectangle, RegularPolygon\n", + "from matplotlib.patches import Rectangle\n", "from matplotlib.collections import PatchCollection" ] }, @@ -180,7 +180,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -218,7 +218,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Canalization - BioModels - Schematas.ipynb b/tutorials/Canalization - BioModels - Schematas.ipynb index 0f7aa9f..c30a21c 100644 --- a/tutorials/Canalization - BioModels - Schematas.ipynb +++ b/tutorials/Canalization - BioModels - Schematas.ipynb @@ -10,15 +10,6 @@ "This tutorial shows how to plot Prime Implicants (F') and Two-Symbol (F'') schematas" ] }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, { "cell_type": "code", "execution_count": 2, @@ -42,6 +33,15 @@ "from cana.datasets.bio import THALIANA #, DROSOPHILA, BUDDING_YEAST" ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, { "cell_type": "code", "execution_count": 4, @@ -272,7 +272,7 @@ "outputs": [ { "data": { - "image/png": "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jNvKOjk5yRWSatzd3bFw4UIAzZvFHT58uM1yxgWgPDw8MH/+fHOFJytrq+v169cRHR2NI0eO4OrVq0hLS8Obb76pWjxERLZMtiSjKzNLbt++jeTkZADAs88+K1dIqlq0aJH0OsTGxuKXX34xOb927VpkZmYCANatW4f77rvP3CHKxprqeuDAAS7GRURkJrItK25syfD29kbfvn3vWP73v/89fvnlF1y7dg1HjhxBRUUFwsPDTfY+sWZarRYZGRmYOnUqDh8+DH9/f8ycOROenp7Izc3Fvn374OTkhA8++ADTp09XO9wusae6KmXevHno2bMnANPpvT4+PlJLEQBkZmbihx9+MHt8RESdIsrk/vvvFwGIzz333F2VHzRokAhA+jdu3DixvLxcrnDaZbyfXq9X/F6iKIq3b98WP/74Y3HcuHFi7969xe7du4u+vr5ifHy8WFxcrOi9L126ZNb6qllXvV5/V3W9du2a2KdPH5P33m9/+9s7XlPpf2fPnr2res6ePVvxWIiI5CKIYou1nlVw6dIlHDx4EG+++SYqKyvxxRdfYMKECYrdz7ictV6vt/n1EaqqqtCnTx8Atl/furo6aQDqnep6+PBhJCQkoKysDFOmTMHf/va3Nsu3vKY9UflPAhHZENWTDKOzZ88iKCgInp6eKC0tVWwAKJMM23QvSUZnrmlPLORPAhHZANl3Ye2sIUOGYPTo0fj5559RXFysdjhERETURRaTZADNAwgB4PLlyypHQkRERF1lMUlGfX09CgoKAABDhw5VORoiIiLqKrMmGXv37sXnn3+OpqYmk+NXrlzBnDlzUFlZicceewwPPPCAOcMiIiIiBci2TsbdOHXqFH7/+9+jT58+CAkJgZubGy5evIijR49Cr9dj4MCB2LJlizlDIiIiIoWYNcl47rnncPHiRezfvx9HjhxBdXU1XFxcMGzYMERHR+P111+Hu7u7OUMiIiIihZg1yXjwwQexYsUKc96SiIiIVGIxAz+JiIjItjDJICIiIkUwySAiIiJFMMkgIiIiRTDJICIiIkWYdXaJJamrq1M7BMW1rKOt19fW60dEZI3sNskw7k5qL+ytvkREpD676y4ZO3as2iGQgsaOHStttNdVWq3W7t4v9lZfIlKWIIqiqHYQREREZHvsriWDiIiIzINJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESni/wOA0OLezqw8BQAAAABJRU5ErkJggg==\n", + "image/png": "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jNvKOjk5yRWSatzd3bFw4UIAzZvFHT58uM1yxgWgPDw8MH/+fHOFJytrq+v169cRHR2NI0eO4OrVq0hLS8Obb76pWjxERLZMtiSjKzNLbt++jeTkZADAs88+K1dIqlq0aJH0OsTGxuKXX34xOb927VpkZmYCANatW4f77rvP3CHKxprqeuDAAS7GRURkJrItK25syfD29kbfvn3vWP73v/89fvnlF1y7dg1HjhxBRUUFwsPDTfY+sWZarRYZGRmYOnUqDh8+DH9/f8ycOROenp7Izc3Fvn374OTkhA8++ADTp09XO9wusae6KmXevHno2bMnANPpvT4+PlJLEQBkZmbihx9+MHt8RESdIsrk/vvvFwGIzz333F2VHzRokAhA+jdu3DixvLxcrnDaZbyfXq9X/F6iKIq3b98WP/74Y3HcuHFi7969xe7du4u+vr5ifHy8WFxcrOi9L126ZNb6qllXvV5/V3W9du2a2KdPH5P33m9/+9s7XlPpf2fPnr2res6ePVvxWIiI5CKIYou1nlVw6dIlHDx4EG+++SYqKyvxxRdfYMKECYrdz7ictV6vt/n1EaqqqtCnTx8Atl/furo6aQDqnep6+PBhJCQkoKysDFOmTMHf/va3Nsu3vKY9UflPAhHZENWTDKOzZ88iKCgInp6eKC0tVWwAKJMM23QvSUZnrmlPLORPAhHZANl3Ye2sIUOGYPTo0fj5559RXFysdjhERETURRaTZADNAwgB4PLlyypHQkRERF1lMUlGfX09CgoKAABDhw5VORoiIiLqKrMmGXv37sXnn3+OpqYmk+NXrlzBnDlzUFlZicceewwPPPCAOcMiIiIiBci2TsbdOHXqFH7/+9+jT58+CAkJgZubGy5evIijR49Cr9dj4MCB2LJlizlDIiIiIoWYNcl47rnncPHiRezfvx9HjhxBdXU1XFxcMGzYMERHR+P111+Hu7u7OUMiIiIihZg1yXjwwQexYsUKc96SiIiIVGIxAz+JiIjItjDJICIiIkUwySAiIiJFMMkgIiIiRTDJICIiIkWYdXaJJamrq1M7BMW1rKOt19fW60dEZI3sNskw7k5qL+ytvkREpD676y4ZO3as2iGQgsaOHStttNdVWq3W7t4v9lZfIlKWIIqiqHYQREREZHvsriWDiIiIzINJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESni/wOA0OLezqw8BQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -314,7 +314,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Canalization - BioModels.ipynb b/tutorials/Canalization - BioModels.ipynb index d3e57dc..dc0b0d1 100644 --- a/tutorials/Canalization - BioModels.ipynb +++ b/tutorials/Canalization - BioModels.ipynb @@ -13,29 +13,29 @@ "execution_count": 1, "metadata": {}, "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "import math\n", "import numpy as np\n", "import pandas as pd\n", - "pd.options.display.float_format = '{:.2g}'.format\n", - "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", "import random\n", "import graphviz\n", "from IPython.display import HTML\n", + "\n", "#\n", - "import cana\n", - "from cana.datasets.bio import THALIANA, DROSOPHILA, BUDDING_YEAST\n", - "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz" + "from cana.datasets.bio import THALIANA # DROSOPHILA, BUDDING_YEAST\n", + "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz\n", + "\n", + "pd.options.display.float_format = '{:.2g}'.format\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" ] }, { @@ -47,7 +47,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], @@ -155,373 +155,373 @@ "\n", "\n", - "\n", "\n", - "\n", - "\n", + "\n", + "\n", "Interaction Graph\n", - "\n", + "\n", "\n", "\n", "0\n", - "\n", - "AP3\n", + "\n", + "AP3\n", "\n", "\n", "\n", "0->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "13\n", - "\n", - "PI\n", + "\n", + "PI\n", "\n", "\n", "\n", "0->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "1\n", - "\n", - "UFO\n", + "\n", + "UFO\n", "\n", "\n", "\n", "1->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "1->1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "2\n", - "\n", - "FUL\n", + "\n", + "FUL\n", "\n", "\n", "\n", "6\n", - "\n", - "LFY\n", + "\n", + "LFY\n", "\n", "\n", "\n", "2->6\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "3\n", - "\n", - "FT\n", + "\n", + "FT\n", "\n", "\n", "\n", "4\n", - "\n", - "AP1\n", + "\n", + "AP1\n", "\n", "\n", "\n", "3->4\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "4->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "4->2\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "4->6\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9\n", - "\n", - "AG\n", + "\n", + "AG\n", "\n", "\n", "\n", "4->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12\n", - "\n", - "TFL1\n", + "\n", + "TFL1\n", "\n", "\n", "\n", "4->12\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "4->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "5\n", - "\n", - "EMF1\n", + "\n", + "EMF1\n", "\n", "\n", "\n", "5->3\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "5->6\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "5->12\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->4\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->5\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->12\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "6->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "14\n", - "\n", - "SEP\n", + "\n", + "SEP\n", "\n", "\n", "\n", "6->14\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "7\n", - "\n", - "AP2\n", + "\n", + "AP2\n", "\n", "\n", "\n", "7->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "7->12\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "8\n", - "\n", - "WUS\n", + "\n", + "WUS\n", "\n", "\n", "\n", "8->8\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "8->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9->4\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9->8\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "9->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "10\n", - "\n", - "LUG\n", + "\n", + "LUG\n", "\n", "\n", "\n", "10->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "11\n", - "\n", - "CLF\n", + "\n", + "CLF\n", "\n", "\n", "\n", "11->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12->2\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12->4\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12->6\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12->7\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "12->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "13->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "13->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "14->0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "14->8\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "14->9\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "14->13\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -583,361 +583,55 @@ "Nodes: 15 | Edges: 41\n" ] }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Error: node 0, position false, expected two doubles\n", + "Error: node 1, position false, expected two doubles\n", + "Error: node 2, position false, expected two doubles\n", + "Error: node 3, position false, expected two doubles\n", + "Error: node 4, position false, expected two doubles\n", + "Error: node 5, position false, expected two doubles\n", + "Error: node 6, position false, expected two doubles\n", + "Error: node 7, position false, expected two doubles\n", + "Error: node 8, position false, expected two doubles\n", + "Error: node 9, position false, expected two doubles\n", + "Error: node 10, position false, expected two doubles\n", + "Error: node 11, position false, expected two doubles\n", + "Error: node 12, position false, expected two doubles\n", + "Error: node 13, position false, expected two doubles\n", + "Error: node 14, position false, expected two doubles\n" + ] + }, + { + "ename": "CalledProcessError", + "evalue": "Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' returned non-zero exit status 1. [stderr: 'Error: node 0, position false, expected two doubles\\nError: node 1, position false, expected two doubles\\nError: node 2, position false, expected two doubles\\nError: node 3, position false, expected two doubles\\nError: node 4, position false, expected two doubles\\nError: node 5, position false, expected two doubles\\nError: node 6, position false, expected two doubles\\nError: node 7, position false, expected two doubles\\nError: node 8, position false, expected two doubles\\nError: node 9, position false, expected two doubles\\nError: node 10, position false, expected two doubles\\nError: node 11, position false, expected two doubles\\nError: node 12, position false, expected two doubles\\nError: node 13, position false, expected two doubles\\nError: node 14, position false, expected two doubles\\n']", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:88\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 88\u001b[0m \u001b[43mproc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_returncode\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[0;32m/usr/lib/python3.12/subprocess.py:502\u001b[0m, in \u001b[0;36mCompletedProcess.check_returncode\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 501\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode:\n\u001b[0;32m--> 502\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout,\n\u001b[1;32m 503\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' returned non-zero exit status 1.", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/IPython/core/formatters.py:977\u001b[0m, in \u001b[0;36mMimeBundleFormatter.__call__\u001b[0;34m(self, obj, include, exclude)\u001b[0m\n\u001b[1;32m 974\u001b[0m method \u001b[38;5;241m=\u001b[39m get_real_method(obj, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprint_method)\n\u001b[1;32m 976\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 977\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmethod\u001b[49m\u001b[43m(\u001b[49m\u001b[43minclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minclude\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexclude\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 978\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 979\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:98\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_mimebundle_\u001b[0;34m(self, include, exclude, **_)\u001b[0m\n\u001b[1;32m 96\u001b[0m include \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(include) \u001b[38;5;28;01mif\u001b[39;00m include \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m {\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_jupyter_mimetype}\n\u001b[1;32m 97\u001b[0m include \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(exclude \u001b[38;5;129;01mor\u001b[39;00m [])\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m {mimetype: \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod_name\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m mimetype, method_name \u001b[38;5;129;01min\u001b[39;00m MIME_TYPES\u001b[38;5;241m.\u001b[39mitems()\n\u001b[1;32m 100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mimetype \u001b[38;5;129;01min\u001b[39;00m include}\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:112\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_image_svg_xml\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 110\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_repr_image_svg_xml\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[1;32m 111\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the rendered graph as SVG string.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 112\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpipe\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43msvg\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mSVG_ENCODING\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:104\u001b[0m, in \u001b[0;36mPipe.pipe\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpipe\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 56\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 57\u001b[0m renderer: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 61\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 62\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[1;32m 63\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the source piped through the Graphviz layout command.\u001b[39;00m\n\u001b[1;32m 64\u001b[0m \n\u001b[1;32m 65\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[38;5;124;03m ' 104\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_legacy\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 105\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 107\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 108\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 109\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 110\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/_tools.py:171\u001b[0m, in \u001b[0;36mdeprecate_positional_args..decorator..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 162\u001b[0m wanted \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvalue\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, value \u001b[38;5;129;01min\u001b[39;00m deprecated\u001b[38;5;241m.\u001b[39mitems())\n\u001b[1;32m 164\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThe signature of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m will be reduced\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 165\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msupported_number\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m positional args\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(supported)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: pass \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mwanted\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 167\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m as keyword arg(s)\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 168\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39mstacklevel,\n\u001b[1;32m 169\u001b[0m category\u001b[38;5;241m=\u001b[39mcategory)\n\u001b[0;32m--> 171\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:121\u001b[0m, in \u001b[0;36mPipe._pipe_legacy\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 112\u001b[0m \u001b[38;5;129m@_tools\u001b[39m\u001b[38;5;241m.\u001b[39mdeprecate_positional_args(supported_number\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m 113\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_pipe_legacy\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 119\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 120\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[0;32m--> 121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_future\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 122\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 123\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 124\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 125\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 126\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 127\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:149\u001b[0m, in \u001b[0;36mPipe._pipe_future\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 146\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m encoding \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 147\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(encoding) \u001b[38;5;129;01mis\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding):\n\u001b[1;32m 148\u001b[0m \u001b[38;5;66;03m# common case: both stdin and stdout need the same encoding\u001b[39;00m\n\u001b[0;32m--> 149\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_lines_string\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 150\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 151\u001b[0m raw \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pipe_lines(\u001b[38;5;241m*\u001b[39margs, input_encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/piping.py:212\u001b[0m, in \u001b[0;36mpipe_lines_string\u001b[0;34m(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)\u001b[0m\n\u001b[1;32m 206\u001b[0m cmd \u001b[38;5;241m=\u001b[39m dot_command\u001b[38;5;241m.\u001b[39mcommand(engine, \u001b[38;5;28mformat\u001b[39m,\n\u001b[1;32m 207\u001b[0m renderer\u001b[38;5;241m=\u001b[39mrenderer,\n\u001b[1;32m 208\u001b[0m formatter\u001b[38;5;241m=\u001b[39mformatter,\n\u001b[1;32m 209\u001b[0m neato_no_op\u001b[38;5;241m=\u001b[39mneato_no_op)\n\u001b[1;32m 210\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minput_lines\u001b[39m\u001b[38;5;124m'\u001b[39m: input_lines, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mencoding\u001b[39m\u001b[38;5;124m'\u001b[39m: encoding}\n\u001b[0;32m--> 212\u001b[0m proc \u001b[38;5;241m=\u001b[39m \u001b[43mexecute\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_check\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcmd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcapture_output\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 213\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\u001b[38;5;241m.\u001b[39mstdout\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:90\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 88\u001b[0m proc\u001b[38;5;241m.\u001b[39mcheck_returncode()\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;241m*\u001b[39me\u001b[38;5;241m.\u001b[39margs)\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' returned non-zero exit status 1. [stderr: 'Error: node 0, position false, expected two doubles\\nError: node 1, position false, expected two doubles\\nError: node 2, position false, expected two doubles\\nError: node 3, position false, expected two doubles\\nError: node 4, position false, expected two doubles\\nError: node 5, position false, expected two doubles\\nError: node 6, position false, expected two doubles\\nError: node 7, position false, expected two doubles\\nError: node 8, position false, expected two doubles\\nError: node 9, position false, expected two doubles\\nError: node 10, position false, expected two doubles\\nError: node 11, position false, expected two doubles\\nError: node 12, position false, expected two doubles\\nError: node 13, position false, expected two doubles\\nError: node 14, position false, expected two doubles\\n']" + ] + }, { "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Effective Graph\n", - "\n", - "\n", - "\n", - "0\n", - "\n", - "AP3\n", - "\n", - "\n", - "\n", - "0->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13\n", - "\n", - "PI\n", - "\n", - "\n", - "\n", - "0->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1\n", - "\n", - "UFO\n", - "\n", - "\n", - "\n", - "1->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1->1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "2\n", - "\n", - "FUL\n", - "\n", - "\n", - "\n", - "3\n", - "\n", - "FT\n", - "\n", - "\n", - "\n", - "4\n", - "\n", - "AP1\n", - "\n", - "\n", - "\n", - "3->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9\n", - "\n", - "AG\n", - "\n", - "\n", - "\n", - "4->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12\n", - "\n", - "TFL1\n", - "\n", - "\n", - "\n", - "4->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5\n", - "\n", - "EMF1\n", - "\n", - "\n", - "\n", - "5->3\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6\n", - "\n", - "LFY\n", - "\n", - "\n", - "\n", - "5->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14\n", - "\n", - "SEP\n", - "\n", - "\n", - "\n", - "6->14\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7\n", - "\n", - "AP2\n", - "\n", - "\n", - "\n", - "7->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8\n", - "\n", - "WUS\n", - "\n", - "\n", - "\n", - "8->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "10\n", - "\n", - "LUG\n", - "\n", - "\n", - "\n", - "10->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "11\n", - "\n", - "CLF\n", - "\n", - "\n", - "\n", - "11->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->7\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->13\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -983,291 +677,15 @@ }, "outputs": [ { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
kk_rk_ek_sk_r*k_e*k_s*k^{out}k_e^{out}k_e^{out} / k^{out}
node
AG96.92.13.50.770.230.3951.50.29
AP374.72.33.50.680.320.4920.480.24
PI63.82.22.50.640.360.4220.230.12
AP142.41.61.90.590.410.4750.850.17
LFY42.81.220.690.310.574.20.6
TFL142.81.220.690.310.552.40.47
WUS31.41.61.30.480.520.4420.770.39
FUL20.751.220.380.62100nan
UFO101001021.50.73
FT101001010.120.12
EMF1101001031.80.58
AP2101001010.270.27
SEP101001040.490.12
LUG000000010.0230.023
CLF000000010.0230.023
\n", - "
" - ], - "text/plain": [ - " k k_r k_e k_s k_r* k_e* k_s* k^{out} k_e^{out} \\\n", - "node \n", - "AG 9 6.9 2.1 3.5 0.77 0.23 0.39 5 1.5 \n", - "AP3 7 4.7 2.3 3.5 0.68 0.32 0.49 2 0.48 \n", - "PI 6 3.8 2.2 2.5 0.64 0.36 0.42 2 0.23 \n", - "AP1 4 2.4 1.6 1.9 0.59 0.41 0.47 5 0.85 \n", - "LFY 4 2.8 1.2 2 0.69 0.31 0.5 7 4.2 \n", - "TFL1 4 2.8 1.2 2 0.69 0.31 0.5 5 2.4 \n", - "WUS 3 1.4 1.6 1.3 0.48 0.52 0.44 2 0.77 \n", - "FUL 2 0.75 1.2 2 0.38 0.62 1 0 0 \n", - "UFO 1 0 1 0 0 1 0 2 1.5 \n", - "FT 1 0 1 0 0 1 0 1 0.12 \n", - "EMF1 1 0 1 0 0 1 0 3 1.8 \n", - "AP2 1 0 1 0 0 1 0 1 0.27 \n", - "SEP 1 0 1 0 0 1 0 4 0.49 \n", - "LUG 0 0 0 0 0 0 0 1 0.023 \n", - "CLF 0 0 0 0 0 0 0 1 0.023 \n", - "\n", - " k_e^{out} / k^{out} \n", - "node \n", - "AG 0.29 \n", - "AP3 0.24 \n", - "PI 0.12 \n", - "AP1 0.17 \n", - "LFY 0.6 \n", - "TFL1 0.47 \n", - "WUS 0.39 \n", - "FUL nan \n", - "UFO 0.73 \n", - "FT 0.12 \n", - "EMF1 0.58 \n", - "AP2 0.27 \n", - "SEP 0.12 \n", - "LUG 0.023 \n", - "CLF 0.023 " - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "TypeError", + "evalue": "BooleanNode.input_symmetry() got an unexpected keyword argument 'norm'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 6\u001b[0m\n\u001b[1;32m 1\u001b[0m df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame({\n\u001b[1;32m 2\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnode\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39mname \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 3\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 4\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_r\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39minput_redundancy(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 5\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39meffective_connectivity(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_s\u001b[39m\u001b[38;5;124m'\u001b[39m:[\u001b[43mn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minput_symmetry\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnorm\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_r*\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39minput_redundancy(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;241m/\u001b[39m n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;28;01mif\u001b[39;00m n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;241m0\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e*\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39meffective_connectivity(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;241m/\u001b[39m n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;28;01mif\u001b[39;00m n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;241m0\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 9\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_s*\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39minput_symmetry(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m N\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 10\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m:[v \u001b[38;5;28;01mfor\u001b[39;00m n,v \u001b[38;5;129;01min\u001b[39;00m Neg\u001b[38;5;241m.\u001b[39mout_degree()],\n\u001b[1;32m 11\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m:[v \u001b[38;5;28;01mfor\u001b[39;00m n,v \u001b[38;5;129;01min\u001b[39;00m Neg\u001b[38;5;241m.\u001b[39mout_degree(weight\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mweight\u001b[39m\u001b[38;5;124m'\u001b[39m)],\n\u001b[1;32m 12\u001b[0m })\u001b[38;5;241m.\u001b[39mset_index(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnode\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 13\u001b[0m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m / k^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m/\u001b[39m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 14\u001b[0m df\u001b[38;5;241m.\u001b[39msort_values(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk\u001b[39m\u001b[38;5;124m'\u001b[39m,ascending\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,inplace\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", + "\u001b[0;31mTypeError\u001b[0m: BooleanNode.input_symmetry() got an unexpected keyword argument 'norm'" + ] } ], "source": [ @@ -1290,14 +708,14 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -1327,7 +745,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "scrolled": false }, @@ -1890,7 +1308,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Canalization - Marques-Pita.ipynb b/tutorials/Canalization - Marques-Pita.ipynb index 484c22b..cf36817 100644 --- a/tutorials/Canalization - Marques-Pita.ipynb +++ b/tutorials/Canalization - Marques-Pita.ipynb @@ -29,14 +29,12 @@ "metadata": {}, "outputs": [], "source": [ - "import networkx as nx\n", "import pandas as pd\n", - "pd.set_option('display.width',200)\n", - "import cana\n", "from cana.datasets.bio import MARQUESPITA\n", "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz\n", - "import matplotlib.pylab as plt\n", - "from IPython.display import Image, display" + "from IPython.display import Image, display\n", + "\n", + "pd.set_option('display.width',200)\n" ] }, { @@ -89,7 +87,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 5, "metadata": { "scrolled": false }, @@ -98,12 +96,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']\n", "k_r: 0.69\n", - "k_e: 0.89\n", - "r_ji: [0.817708333333333, 0.4270833333333333, 0.4270833333333333, 0.817708333333333, 0.817708333333333, 0.817708333333333] (mean)\n", - "e_ji: [0.18229166666666696, 0.5729166666666667, 0.5729166666666667, 0.18229166666666696, 0.18229166666666696, 0.18229166666666696] (mean)\n" + "k_e: 0.31\n", + "r_ji: [0.8177083333333334, 0.4270833333333333, 0.4270833333333333, 0.8177083333333334, 0.8177083333333334, 0.8177083333333334] (mean)\n", + "e_ji: [0.18229166666666663, 0.5729166666666667, 0.5729166666666667, 0.18229166666666663, 0.18229166666666663, 0.18229166666666663] (mean)\n" ] } ], @@ -120,7 +118,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -245,7 +243,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -276,89 +274,89 @@ " \n", " \n", " \n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", " \n", " \n", " \n", " \n", " 0\n", - " ##0###\n", + " 1##111\n", " 0\n", " \n", " \n", " 1\n", - " 0##000\n", + " ##0###\n", " 0\n", " \n", " \n", " 2\n", - " 1##111\n", + " #1####\n", " 0\n", " \n", " \n", " 3\n", - " #1####\n", + " 0##000\n", " 0\n", " \n", " \n", " 4\n", - " #011#0\n", + " 101#0#\n", " 1\n", " \n", " \n", " 5\n", - " 0011##\n", + " #011#0\n", " 1\n", " \n", " \n", " 6\n", - " 101#0#\n", + " 001##1\n", " 1\n", " \n", " \n", " 7\n", - " 001##1\n", + " #0101#\n", " 1\n", " \n", " \n", " 8\n", - " #0110#\n", + " 0011##\n", " 1\n", " \n", " \n", " 9\n", - " #010#1\n", + " #01#10\n", " 1\n", " \n", " \n", " 10\n", - " #01#10\n", + " 1010##\n", " 1\n", " \n", " \n", " 11\n", - " #0101#\n", + " #01#01\n", " 1\n", " \n", " \n", " 12\n", - " 001#1#\n", + " #0110#\n", " 1\n", " \n", " \n", " 13\n", - " #01#01\n", + " #010#1\n", " 1\n", " \n", " \n", " 14\n", - " 1010##\n", + " 101##0\n", " 1\n", " \n", " \n", " 15\n", - " 101##0\n", + " 001#1#\n", " 1\n", " \n", " \n", @@ -366,23 +364,23 @@ "" ], "text/plain": [ - " In: Out:\n", - "0 ##0### 0\n", - "1 0##000 0\n", - "2 1##111 0\n", - "3 #1#### 0\n", - "4 #011#0 1\n", - "5 0011## 1\n", - "6 101#0# 1\n", - "7 001##1 1\n", - "8 #0110# 1\n", - "9 #010#1 1\n", - "10 #01#10 1\n", - "11 #0101# 1\n", - "12 001#1# 1\n", - "13 #01#01 1\n", - "14 1010## 1\n", - "15 101##0 1" + " Input Output\n", + "0 1##111 0\n", + "1 ##0### 0\n", + "2 #1#### 0\n", + "3 0##000 0\n", + "4 101#0# 1\n", + "5 #011#0 1\n", + "6 001##1 1\n", + "7 #0101# 1\n", + "8 0011## 1\n", + "9 #01#10 1\n", + "10 1010## 1\n", + "11 #01#01 1\n", + "12 #0110# 1\n", + "13 #010#1 1\n", + "14 101##0 1\n", + "15 001#1# 1" ] }, "metadata": {}, @@ -397,7 +395,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -408,71 +406,16 @@ ] }, { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
In:Out:
01##1110
1#1####0
2##0###0
30##0000
41ÌŠ010ÌŠ#ÌŠ#ÌŠ1
\n", - "
" - ], - "text/plain": [ - " In: Out:\n", - "0 1##111 0\n", - "1 #1#### 0\n", - "2 ##0### 0\n", - "3 0##000 0\n", - "4 1ÌŠ010ÌŠ#ÌŠ#ÌŠ 1" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTW Schema\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m----> 2\u001b[0m dfTW \u001b[38;5;241m=\u001b[39m \u001b[43mn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mschemata_look_up_table\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mtype\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mts\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m display(dfTW)\n", + "File \u001b[0;32m/data/siyer/CANA/cana/boolean_node.py:498\u001b[0m, in \u001b[0;36mBooleanNode.schemata_look_up_table\u001b[0;34m(self, type, pi_symbol, ts_symbol_list)\u001b[0m\n\u001b[1;32m 496\u001b[0m \u001b[38;5;66;03m# Same Symbol\u001b[39;00m\n\u001b[1;32m 497\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m j, samesymbol \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(samesymbols):\n\u001b[0;32m--> 498\u001b[0m ts_symbol_unicode \u001b[38;5;241m=\u001b[39m \u001b[43mts_symbol_list\u001b[49m\u001b[43m[\u001b[49m\u001b[43mj\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 499\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m j \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 500\u001b[0m string \u001b[38;5;241m+\u001b[39m\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[0;31mIndexError\u001b[0m: list index out of range" + ] } ], "source": [ @@ -483,7 +426,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -514,7 +457,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -858,7 +801,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Canalization - Node Schematas.ipynb b/tutorials/Canalization - Node Schematas.ipynb index 42984df..4aacc98 100644 --- a/tutorials/Canalization - Node Schematas.ipynb +++ b/tutorials/Canalization - Node Schematas.ipynb @@ -14,9 +14,11 @@ "metadata": {}, "outputs": [], "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "%matplotlib inline" + "from __future__ import division\n", + "import pandas as pd\n", + "from IPython.display import display\n", + "from cana.datasets.bools import OR, AND, XOR, CONTRADICTION, COPYx1, RULE110, RULE90\n", + "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz" ] }, { @@ -25,13 +27,9 @@ "metadata": {}, "outputs": [], "source": [ - "from __future__ import division\n", - "import numpy as np\n", - "import pandas as pd\n", - "from IPython.display import Image, display\n", - "import cana\n", - "from cana.datasets.bools import *\n", - "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz" + "%load_ext autoreload\n", + "%autoreload 2\n", + "%matplotlib inline" ] }, { @@ -43,9 +41,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.38\n", - "k_e: 0.81\n", + "k_e: 0.62\n", "r_ji: [0.375, 0.375] (mean)\n", "e_ji: [0.625, 0.625] (mean)\n" ] @@ -79,10 +77,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -91,25 +89,25 @@ " 00\n", " 0\n", " 00\n", - " 0\n", - " 00\n", - " 0\n", + " 0.0\n", + " (00) | (0ÌŠ0ÌŠ)\n", + " 0.0\n", " \n", " \n", " 1\n", " 01\n", " 1\n", " 1#\n", - " 1\n", - " #ÌŠ1ÌŠ\n", - " 1\n", + " 1.0\n", + " (1ÌŠ#ÌŠ)\n", + " 1.0\n", " \n", " \n", " 2\n", " 10\n", " 1\n", " #1\n", - " 1\n", + " 1.0\n", " -\n", " -\n", " \n", @@ -127,12 +125,12 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 00 0 00 0 00 0\n", - "1 01 1 1# 1 #ÌŠ1ÌŠ 1\n", - "2 10 1 #1 1 - -\n", - "3 11 1 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 00 0 00 0.0 (00) | (0ÌŠ0ÌŠ) 0.0\n", + "1 01 1 1# 1.0 (1ÌŠ#ÌŠ) 1.0\n", + "2 10 1 #1 1.0 - -\n", + "3 11 1 - - - -" ] }, "metadata": {}, @@ -144,12 +142,13 @@ "\n", "\n", - "\n", - "\n", + "\n", "\n", "\n", + "%3\n", "\n", "\n", "\n", @@ -248,7 +247,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 3, @@ -281,9 +280,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 1.00\n", - "k_e: 0.50\n", + "k_e: 0.00\n", "r_ji: [1.0, 1.0] (mean)\n", "e_ji: [0.0, 0.0] (mean)\n" ] @@ -317,10 +316,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -329,9 +328,9 @@ " 00\n", " 0\n", " ##\n", - " 0\n", - " ##\n", - " 0\n", + " 0.0\n", + " (##) | (#ÌŠ#ÌŠ)\n", + " 0.0\n", " \n", " \n", " 1\n", @@ -365,12 +364,12 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 00 0 ## 0 ## 0\n", - "1 01 0 - - - -\n", - "2 10 0 - - - -\n", - "3 11 0 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 00 0 ## 0.0 (##) | (#ÌŠ#ÌŠ) 0.0\n", + "1 01 0 - - - -\n", + "2 10 0 - - - -\n", + "3 11 0 - - - -" ] }, "metadata": {}, @@ -382,12 +381,13 @@ "\n", "\n", - "\n", - "\n", + "\n", "\n", "\n", + "%3\n", "\n", "\n", "\n", @@ -417,7 +417,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 4, @@ -451,13 +451,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.00\n", "k_e: 1.00\n", "r_ji: [0.0, 0.0] (mean)\n", "e_ji: [1.0, 1.0] (mean)\n", - "TS: 11 | PermIdx: [] | SameIdx: [[0, 1]]\n", "TS: 00 | PermIdx: [] | SameIdx: [[0, 1]]\n", + "TS: 11 | PermIdx: [] | SameIdx: [[0, 1]]\n", "TS: 01 | PermIdx: [[0, 1]] | SameIdx: []\n" ] }, @@ -490,10 +490,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -501,19 +501,19 @@ " 0\n", " 00\n", " 0\n", - " 11\n", - " 0\n", - " 11\n", + " 00\n", " 0\n", + " (00) | (0ÌŠ0ÌŠ)\n", + " 0.0\n", " \n", " \n", " 1\n", " 01\n", " 1\n", - " 00\n", - " 0\n", - " 00\n", + " 11\n", " 0\n", + " (11) | (1ÌŠ1ÌŠ)\n", + " 0.0\n", " \n", " \n", " 2\n", @@ -521,8 +521,8 @@ " 1\n", " 01\n", " 1\n", - " 0ÌŠ1ÌŠ\n", - " 1\n", + " (0ÌŠ1ÌŠ)\n", + " 1.0\n", " \n", " \n", " 3\n", @@ -538,12 +538,12 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 00 0 11 0 11 0\n", - "1 01 1 00 0 00 0\n", - "2 10 1 01 1 0ÌŠ1ÌŠ 1\n", - "3 11 0 10 1 - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 00 0 00 0 (00) | (0ÌŠ0ÌŠ) 0.0\n", + "1 01 1 11 0 (11) | (1ÌŠ1ÌŠ) 0.0\n", + "2 10 1 01 1 (0ÌŠ1ÌŠ) 1.0\n", + "3 11 0 10 1 - -" ] }, "metadata": {}, @@ -555,156 +555,157 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-0-out-0\n", - "\n", - "XOR\n", + "\n", + "XOR\n", "\n", "\n", "\n", "var-0-out-1\n", - "\n", - "XOR\n", + "\n", + "XOR\n", "\n", "\n", "\n", "thr-0-var-0-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-0-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1\n", - "\n", - "1\n", + "var-1-out-0\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1->thr-0-var-0-out-0\n", - "\n", - "\n", + "var-1-out-0->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "var-1-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1\n", - "\n", - "2\n", + "var-2-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1->thr-0-var-0-out-0\n", - "\n", - "\n", + "var-2-out-0->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "var-2-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", "\n", "\n", "thr-1-var-0-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-1-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0\n", - "\n", - "1\n", + "var-1-out-1\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->thr-1-var-0-out-0\n", - "\n", - "\n", + "var-1-out-1->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "var-1-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0\n", - "\n", - "2\n", + "var-2-out-1\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0->thr-1-var-0-out-0\n", - "\n", - "\n", + "var-2-out-1->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "var-2-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", "\n", "\n", "thr-2-var-0-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-2-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-2-var-0-out-0->thr-2-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-2-var-0-out-1->thr-2-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -741,9 +742,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.38\n", - "k_e: 0.81\n", + "k_e: 0.62\n", "r_ji: [0.375, 0.375] (mean)\n", "e_ji: [0.625, 0.625] (mean)\n" ] @@ -777,10 +778,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -788,26 +789,26 @@ " 0\n", " 00\n", " 0\n", - " 0#\n", - " 0\n", - " 0ÌŠ#ÌŠ\n", - " 0\n", + " #0\n", + " 0.0\n", + " (0ÌŠ#ÌŠ)\n", + " 0.0\n", " \n", "
\n", " 1\n", " 01\n", " 0\n", - " #0\n", - " 0\n", - " 11\n", - " 1\n", + " 0#\n", + " 0.0\n", + " (11) | (1ÌŠ1ÌŠ)\n", + " 1.0\n", "
\n", "
\n", " 2\n", " 10\n", " 0\n", " 11\n", - " 1\n", + " 1.0\n", " -\n", " -\n", "
\n", @@ -825,12 +826,12 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 00 0 0# 0 0ÌŠ#ÌŠ 0\n", - "1 01 0 #0 0 11 1\n", - "2 10 0 11 1 - -\n", - "3 11 1 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 00 0 #0 0.0 (0ÌŠ#ÌŠ) 0.0\n", + "1 01 0 0# 0.0 (11) | (1ÌŠ1ÌŠ) 1.0\n", + "2 10 0 11 1.0 - -\n", + "3 11 1 - - - -" ] }, "metadata": {}, @@ -842,12 +843,13 @@ "\n", "\n", - "\n", - "\n", + "\n", "\n", "\n", + "%3\n", "\n", "\n", "\n", @@ -946,7 +948,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -977,9 +979,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.50\n", - "k_e: 0.75\n", + "k_e: 0.50\n", "r_ji: [0.0, 1.0] (mean)\n", "e_ji: [1.0, 0.0] (mean)\n" ] @@ -1013,10 +1015,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -1025,18 +1027,18 @@ " 00\n", " 0\n", " 0#\n", - " 0\n", - " 0#\n", - " 0\n", + " 0.0\n", + " (0#)\n", + " 0.0\n", " \n", "
\n", " 1\n", " 01\n", " 0\n", " 1#\n", - " 1\n", - " 1#\n", - " 1\n", + " 1.0\n", + " (1#)\n", + " 1.0\n", "
\n", "
\n", " 2\n", @@ -1061,12 +1063,12 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 00 0 0# 0 0# 0\n", - "1 01 0 1# 1 1# 1\n", - "2 10 1 - - - -\n", - "3 11 1 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 00 0 0# 0.0 (0#) 0.0\n", + "1 01 0 1# 1.0 (1#) 1.0\n", + "2 10 1 - - - -\n", + "3 11 1 - - - -" ] }, "metadata": {}, @@ -1078,12 +1080,13 @@ "\n", "\n", - "\n", - "\n", + "\n", "\n", "\n", + "%3\n", "\n", "\n", "\n", @@ -1149,7 +1152,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -1181,9 +1184,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.33\n", - "k_e: 0.89\n", + "k_e: 0.67\n", "r_ji: [0.0, 1.0, 0.0] (mean)\n", "e_ji: [1.0, 0.0, 1.0] (mean)\n" ] @@ -1217,10 +1220,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", "
\n", " \n", " \n", @@ -1228,35 +1231,35 @@ " 0\n", " 000\n", " 0\n", - " 0#0\n", - " 0\n", - " 0#0\n", - " 0\n", + " 1#1\n", + " 0.0\n", + " (1#1) | (1ÌŠ#1ÌŠ)\n", + " 0.0\n", " \n", "
\n", " 1\n", " 001\n", " 1\n", - " 1#1\n", - " 0\n", - " 1#1\n", - " 0\n", + " 0#0\n", + " 0.0\n", + " (0#0) | (0ÌŠ#0ÌŠ)\n", + " 0.0\n", "
\n", "
\n", " 2\n", " 010\n", " 0\n", - " 1#0\n", - " 1\n", - " 0ÌŠ#1ÌŠ\n", - " 1\n", + " 0#1\n", + " 1.0\n", + " (0ÌŠ#1ÌŠ)\n", + " 1.0\n", "
\n", "
\n", " 3\n", " 011\n", " 1\n", - " 0#1\n", - " 1\n", + " 1#0\n", + " 1.0\n", " -\n", " -\n", "
\n", @@ -1301,16 +1304,16 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 000 0 0#0 0 0#0 0\n", - "1 001 1 1#1 0 1#1 0\n", - "2 010 0 1#0 1 0ÌŠ#1ÌŠ 1\n", - "3 011 1 0#1 1 - -\n", - "4 100 1 - - - -\n", - "5 101 0 - - - -\n", - "6 110 1 - - - -\n", - "7 111 0 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 000 0 1#1 0.0 (1#1) | (1ÌŠ#1ÌŠ) 0.0\n", + "1 001 1 0#0 0.0 (0#0) | (0ÌŠ#0ÌŠ) 0.0\n", + "2 010 0 0#1 1.0 (0ÌŠ#1ÌŠ) 1.0\n", + "3 011 1 1#0 1.0 - -\n", + "4 100 1 - - - -\n", + "5 101 0 - - - -\n", + "6 110 1 - - - -\n", + "7 111 0 - - - -" ] }, "metadata": {}, @@ -1322,156 +1325,157 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-0-out-0\n", - "\n", - "R90\n", + "\n", + "R90\n", "\n", "\n", "\n", "var-0-out-1\n", - "\n", - "R90\n", + "\n", + "R90\n", "\n", "\n", "\n", "thr-0-var-0-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-0-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0\n", - "\n", - "1\n", + "var-1-out-1\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", + "var-1-out-1->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "var-1-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-0\n", - "\n", - "3\n", + "var-3-out-1\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-3-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", + "var-3-out-1->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "var-3-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", "\n", "\n", "thr-1-var-0-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-1-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1\n", - "\n", - "1\n", + "var-1-out-0\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1->thr-1-var-0-out-0\n", - "\n", - "\n", + "var-1-out-0->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "var-1-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-1\n", - "\n", - "3\n", + "var-3-out-0\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-3-out-1->thr-1-var-0-out-0\n", - "\n", - "\n", + "var-3-out-0->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "var-3-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", "\n", "\n", "thr-2-var-0-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-2-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-2-var-0-out-0->thr-2-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-2-var-0-out-1->thr-2-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 8, @@ -1503,9 +1507,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", + "\n", "k_r: 0.29\n", - "k_e: 0.90\n", + "k_e: 0.71\n", "r_ji: [0.625, 0.125, 0.125] (mean)\n", "e_ji: [0.375, 0.875, 0.875] (mean)\n" ] @@ -1539,10 +1543,10 @@ " \n", " In:\n", " Out:\n", - " In:\n", - " Out:\n", - " In:\n", - " Out:\n", + " Input\n", + " Output\n", + " Input\n", + " Output\n", " \n", " \n", " \n", @@ -1551,54 +1555,54 @@ " 000\n", " 0\n", " #00\n", - " 0\n", - " #00\n", - " 0\n", + " 0.0\n", + " (#00) | (#0ÌŠ0ÌŠ)\n", + " 0.0\n", " \n", "
\n", " 1\n", " 001\n", " 1\n", " 111\n", - " 0\n", - " 111\n", - " 0\n", + " 0.0\n", + " (111) | (1ÌŠ1ÌŠ1ÌŠ)\n", + " 0.0\n", "
\n", "
\n", " 2\n", " 010\n", " 1\n", - " #01\n", - " 1\n", - " 0#ÌŠ1ÌŠ\n", - " 1\n", + " 01#\n", + " 1.0\n", + " (0ÌŠ#ÌŠ1)\n", + " 1.0\n", "
\n", "
\n", " 3\n", " 011\n", " 1\n", - " #10\n", - " 1\n", - " #ÌŠ10ÌŠ\n", - " 1\n", + " #01\n", + " 1.0\n", + " (#0ÌŠ1ÌŠ)\n", + " 1.0\n", "
\n", "
\n", " 4\n", " 100\n", " 0\n", " 0#1\n", - " 1\n", - " 0ÌŠ#ÌŠ1\n", - " 1\n", + " 1.0\n", + " (01ÌŠ#ÌŠ)\n", + " 1.0\n", "
\n", "
\n", " 5\n", " 101\n", " 1\n", - " 01#\n", - " 1\n", - " #1ÌŠ0ÌŠ\n", - " 1\n", + " #10\n", + " 1.0\n", + " (0ÌŠ1#ÌŠ)\n", + " 1.0\n", "
\n", "
\n", " 6\n", @@ -1623,312 +1627,321 @@ "" ], "text/plain": [ - " Original LUT PI Schema TS Schema \n", - " In: Out: In: Out: In: Out:\n", - "0 000 0 #00 0 #00 0\n", - "1 001 1 111 0 111 0\n", - "2 010 1 #01 1 0#ÌŠ1ÌŠ 1\n", - "3 011 1 #10 1 #ÌŠ10ÌŠ 1\n", - "4 100 0 0#1 1 0ÌŠ#ÌŠ1 1\n", - "5 101 1 01# 1 #1ÌŠ0ÌŠ 1\n", - "6 110 1 - - - -\n", - "7 111 0 - - - -" + " Original LUT PI Schema TS Schema \n", + " In: Out: Input Output Input Output\n", + "0 000 0 #00 0.0 (#00) | (#0ÌŠ0ÌŠ) 0.0\n", + "1 001 1 111 0.0 (111) | (1ÌŠ1ÌŠ1ÌŠ) 0.0\n", + "2 010 1 01# 1.0 (0ÌŠ#ÌŠ1) 1.0\n", + "3 011 1 #01 1.0 (#0ÌŠ1ÌŠ) 1.0\n", + "4 100 0 0#1 1.0 (01ÌŠ#ÌŠ) 1.0\n", + "5 101 1 #10 1.0 (0ÌŠ1#ÌŠ) 1.0\n", + "6 110 1 - - - -\n", + "7 111 0 - - - -" ] }, "metadata": {}, "output_type": "display_data" }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Warning: node 'var-0-out-0', graph '%3' size too small for label\n", + "Warning: node 'var-0-out-1', graph '%3' size too small for label\n" + ] + }, { "data": { "image/svg+xml": [ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-0-out-0\n", - "\n", - "R110\n", + "\n", + "R110\n", "\n", "\n", "\n", "var-0-out-1\n", - "\n", - "R110\n", + "\n", + "R110\n", "\n", "\n", "\n", "thr-0-var-0-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-0-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-2-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-2-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-4-var-0-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0->fus-0-thr-4-var-0-out-0\n", - "\n", + "var-2-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-5-var-0-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0->fus-0-thr-5-var-0-out-0\n", - "\n", + "var-2-out-0->fus-0-thr-3-var-0-out-0\n", + "\n", "\n", "\n", "\n", "var-3-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-3-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-3-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-5-var-0-out-0\n", + "\n", "\n", "\n", "\n", "var-3-out-0->fus-0-thr-5-var-0-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "thr-1-var-0-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "thr-1-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-1-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", "\n", "var-1-out-1->thr-1-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-2-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-2-out-1->thr-1-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "var-2-out-1->fus-0-thr-3-var-0-out-1\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-0-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "fus-0-thr-4-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1->thr-3-var-0-out-1\n", - "\n", - "\n", + "var-2-out-1->fus-0-thr-4-var-0-out-1\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-5-var-0-out-1\n", - "\n", + "\n", + "\n", + "thr-5-var-0-out-1\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-2-out-1->fus-0-thr-5-var-0-out-1\n", - "\n", + "var-2-out-1->thr-5-var-0-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-3-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-3-out-1->thr-1-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-3-out-1->fus-0-thr-2-var-0-out-1\n", - "\n", + "\n", + "\n", + "thr-2-var-0-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "thr-4-var-0-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "var-3-out-1->thr-2-var-0-out-1\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-1->thr-4-var-0-out-1\n", - "\n", - "\n", + "var-3-out-1->fus-0-thr-3-var-0-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-3-out-1->fus-0-thr-5-var-0-out-1\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-0-out-1\n", - "\n", - "2\n", + "var-3-out-1->fus-0-thr-4-var-0-out-1\n", + "\n", "\n", "\n", "\n", "thr-2-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-0->thr-2-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-0\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "var-1-out-0->thr-2-var-0-out-1\n", - "\n", - "\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", + "var-1-out-0->fus-0-thr-2-var-0-out-0\n", + "\n", "\n", - "\n", + "\n", + "\n", + "thr-4-var-0-out-1\n", + "\n", + "2\n", + "\n", + "\n", "\n", - "var-1-out-0->fus-0-thr-4-var-0-out-0\n", - "\n", + "var-1-out-0->thr-4-var-0-out-1\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-2-var-0-out-1->thr-2-var-0-out-1\n", - "\n", - "\n", + "var-1-out-0->fus-0-thr-5-var-0-out-0\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-0-out-1\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-3-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-3-var-0-out-0->thr-3-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "thr-4-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "fus-0-thr-3-var-0-out-1->thr-3-var-0-out-1\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-4-var-0-out-0->thr-4-var-0-out-1\n", - "\n", - "\n", + "thr-4-var-0-out-1->var-0-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-5-var-0-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "fus-0-thr-4-var-0-out-1->thr-4-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-5-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", - "fus-0-thr-5-var-0-out-0->thr-5-var-0-out-1\n", - "\n", - "\n", - "\n", - "\n", "\n", - "fus-0-thr-5-var-0-out-1->thr-5-var-0-out-1\n", - "\n", - "\n", + "fus-0-thr-5-var-0-out-0->thr-5-var-0-out-1\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 9, @@ -1975,7 +1988,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Control - BioModels - Driver Variables.ipynb b/tutorials/Control - BioModels - Driver Variables.ipynb index a633ca2..8922ec0 100644 --- a/tutorials/Control - BioModels - Driver Variables.ipynb +++ b/tutorials/Control - BioModels - Driver Variables.ipynb @@ -16,9 +16,7 @@ "source": [ "import graphviz\n", "import math\n", - "import matplotlib.pyplot as plt\n", "#\n", - "import cana\n", "from cana.datasets.bio import THALIANA #, DROSOPHILA, BUDDING_YEAST" ] }, @@ -31,7 +29,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], @@ -49,7 +47,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "STG: Arabidopsis Thaliana\n", + "DiGraph named 'STG: Arabidopsis thaliana' with 8192 nodes and 8192 edges\n", "[[1643], [865], [132], [148], [7787], [7011], [2180], [2196], [5739], [4963]]\n", "Nodes: 8192 | Edges: 8192\n" ] @@ -73,17 +71,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/rionbr/Sites/CANA/cana/boolean_network.py:848: UserWarning: Cannot control a constant variable 'LUG'! Skipping\n", - " warnings.warn(\"Cannot control a constant variable '%s'! Skipping\" % self.nodes[dv].name )\n", - "/Users/rionbr/Sites/CANA/cana/boolean_network.py:848: UserWarning: Cannot control a constant variable 'CLF'! Skipping\n", - " warnings.warn(\"Cannot control a constant variable '%s'! Skipping\" % self.nodes[dv].name )\n" + "/data/siyer/CANA/cana/boolean_network.py:1065: UserWarning: Cannot control a constant variable 'LUG'! Skipping\n", + " warnings.warn(\n", + "/data/siyer/CANA/cana/boolean_network.py:1065: UserWarning: Cannot control a constant variable 'CLF'! Skipping\n", + " warnings.warn(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "C-STG: Arabidopsis Thaliana (UFO,LUG,CLF,TFL1,SEP)\n", + "DiGraph named 'C-STG: Arabidopsis thaliana (UFO,LUG,CLF,TFL1,SEP)' with 8192 nodes and 73701 edges\n", "Nodes: 8192 | Edges: 73701\n" ] } @@ -107,9 +105,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "CAG: C-STG: Arabidopsis Thaliana Att(UFO,LUG,CLF,TFL1,SEP)\n", + "DiGraph named 'CAG: C-STG: Arabidopsis thaliana Att(UFO,LUG,CLF,TFL1,SEP)' with 10 nodes and 37 edges\n", "Nodes: 10 | Edges: 37\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/data/siyer/CANA/cana/boolean_network.py:1216: UserWarning: Cannot control a constant variable 'LUG'! Skipping\n", + " warnings.warn(\n", + "/data/siyer/CANA/cana/boolean_network.py:1216: UserWarning: Cannot control a constant variable 'CLF'! Skipping\n", + " warnings.warn(\n" + ] } ], "source": [ @@ -155,7 +163,7 @@ "\n", "\n", - "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -458,379 +466,41 @@ "execution_count": 9, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "free(): invalid next size (normal)\n" + ] + }, + { + "ename": "CalledProcessError", + "evalue": "Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with . [stderr: 'free(): invalid next size (normal)\\n']", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:88\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 88\u001b[0m \u001b[43mproc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_returncode\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[0;32m/usr/lib/python3.12/subprocess.py:502\u001b[0m, in \u001b[0;36mCompletedProcess.check_returncode\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 501\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode:\n\u001b[0;32m--> 502\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout,\n\u001b[1;32m 503\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with .", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/IPython/core/formatters.py:977\u001b[0m, in \u001b[0;36mMimeBundleFormatter.__call__\u001b[0;34m(self, obj, include, exclude)\u001b[0m\n\u001b[1;32m 974\u001b[0m method \u001b[38;5;241m=\u001b[39m get_real_method(obj, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprint_method)\n\u001b[1;32m 976\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 977\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmethod\u001b[49m\u001b[43m(\u001b[49m\u001b[43minclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minclude\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexclude\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 978\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 979\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:98\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_mimebundle_\u001b[0;34m(self, include, exclude, **_)\u001b[0m\n\u001b[1;32m 96\u001b[0m include \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(include) \u001b[38;5;28;01mif\u001b[39;00m include \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m {\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_jupyter_mimetype}\n\u001b[1;32m 97\u001b[0m include \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(exclude \u001b[38;5;129;01mor\u001b[39;00m [])\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m {mimetype: \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod_name\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m mimetype, method_name \u001b[38;5;129;01min\u001b[39;00m MIME_TYPES\u001b[38;5;241m.\u001b[39mitems()\n\u001b[1;32m 100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mimetype \u001b[38;5;129;01min\u001b[39;00m include}\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:112\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_image_svg_xml\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 110\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_repr_image_svg_xml\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[1;32m 111\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the rendered graph as SVG string.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 112\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpipe\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43msvg\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mSVG_ENCODING\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:104\u001b[0m, in \u001b[0;36mPipe.pipe\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpipe\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 56\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 57\u001b[0m renderer: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 61\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 62\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[1;32m 63\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the source piped through the Graphviz layout command.\u001b[39;00m\n\u001b[1;32m 64\u001b[0m \n\u001b[1;32m 65\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[38;5;124;03m ' 104\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_legacy\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 105\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 107\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 108\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 109\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 110\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/_tools.py:171\u001b[0m, in \u001b[0;36mdeprecate_positional_args..decorator..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 162\u001b[0m wanted \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvalue\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, value \u001b[38;5;129;01min\u001b[39;00m deprecated\u001b[38;5;241m.\u001b[39mitems())\n\u001b[1;32m 164\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThe signature of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m will be reduced\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 165\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msupported_number\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m positional args\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(supported)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: pass \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mwanted\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 167\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m as keyword arg(s)\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 168\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39mstacklevel,\n\u001b[1;32m 169\u001b[0m category\u001b[38;5;241m=\u001b[39mcategory)\n\u001b[0;32m--> 171\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:121\u001b[0m, in \u001b[0;36mPipe._pipe_legacy\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 112\u001b[0m \u001b[38;5;129m@_tools\u001b[39m\u001b[38;5;241m.\u001b[39mdeprecate_positional_args(supported_number\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m 113\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_pipe_legacy\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 119\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 120\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[0;32m--> 121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_future\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 122\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 123\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 124\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 125\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 126\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 127\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:149\u001b[0m, in \u001b[0;36mPipe._pipe_future\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 146\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m encoding \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 147\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(encoding) \u001b[38;5;129;01mis\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding):\n\u001b[1;32m 148\u001b[0m \u001b[38;5;66;03m# common case: both stdin and stdout need the same encoding\u001b[39;00m\n\u001b[0;32m--> 149\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_lines_string\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 150\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 151\u001b[0m raw \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pipe_lines(\u001b[38;5;241m*\u001b[39margs, input_encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/piping.py:212\u001b[0m, in \u001b[0;36mpipe_lines_string\u001b[0;34m(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)\u001b[0m\n\u001b[1;32m 206\u001b[0m cmd \u001b[38;5;241m=\u001b[39m dot_command\u001b[38;5;241m.\u001b[39mcommand(engine, \u001b[38;5;28mformat\u001b[39m,\n\u001b[1;32m 207\u001b[0m renderer\u001b[38;5;241m=\u001b[39mrenderer,\n\u001b[1;32m 208\u001b[0m formatter\u001b[38;5;241m=\u001b[39mformatter,\n\u001b[1;32m 209\u001b[0m neato_no_op\u001b[38;5;241m=\u001b[39mneato_no_op)\n\u001b[1;32m 210\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minput_lines\u001b[39m\u001b[38;5;124m'\u001b[39m: input_lines, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mencoding\u001b[39m\u001b[38;5;124m'\u001b[39m: encoding}\n\u001b[0;32m--> 212\u001b[0m proc \u001b[38;5;241m=\u001b[39m \u001b[43mexecute\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_check\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcmd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcapture_output\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 213\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\u001b[38;5;241m.\u001b[39mstdout\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:90\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 88\u001b[0m proc\u001b[38;5;241m.\u001b[39mcheck_returncode()\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;241m*\u001b[39me\u001b[38;5;241m.\u001b[39margs)\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with . [stderr: 'free(): invalid next size (normal)\\n']" + ] + }, { "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Structural Graph\n", - "\n", - "\n", - "\n", - "0\n", - "\n", - "AP3\n", - "\n", - "\n", - "\n", - "0->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13\n", - "\n", - "PI\n", - "\n", - "\n", - "\n", - "0->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1\n", - "\n", - "UFO\n", - "\n", - "\n", - "\n", - "1->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1->1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "2\n", - "\n", - "FUL\n", - "\n", - "\n", - "\n", - "6\n", - "\n", - "LFY\n", - "\n", - "\n", - "\n", - "2->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "3\n", - "\n", - "FT\n", - "\n", - "\n", - "\n", - "4\n", - "\n", - "AP1\n", - "\n", - "\n", - "\n", - "3->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9\n", - "\n", - "AG\n", - "\n", - "\n", - "\n", - "4->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12\n", - "\n", - "TFL1\n", - "\n", - "\n", - "\n", - "4->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5\n", - "\n", - "EMF1\n", - "\n", - "\n", - "\n", - "5->3\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14\n", - "\n", - "SEP\n", - "\n", - "\n", - "\n", - "6->14\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7\n", - "\n", - "AP2\n", - "\n", - "\n", - "\n", - "7->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8\n", - "\n", - "WUS\n", - "\n", - "\n", - "\n", - "8->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "10\n", - "\n", - "LUG\n", - "\n", - "\n", - "\n", - "10->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "11\n", - "\n", - "CLF\n", - "\n", - "\n", - "\n", - "11->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->7\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->13\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -893,361 +563,41 @@ "execution_count": 11, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "double free or corruption (!prev)\n" + ] + }, + { + "ename": "CalledProcessError", + "evalue": "Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with . [stderr: 'double free or corruption (!prev)\\n']", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:88\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 88\u001b[0m \u001b[43mproc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_returncode\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n", + "File \u001b[0;32m/usr/lib/python3.12/subprocess.py:502\u001b[0m, in \u001b[0;36mCompletedProcess.check_returncode\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 501\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode:\n\u001b[0;32m--> 502\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreturncode, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout,\n\u001b[1;32m 503\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with .", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/IPython/core/formatters.py:977\u001b[0m, in \u001b[0;36mMimeBundleFormatter.__call__\u001b[0;34m(self, obj, include, exclude)\u001b[0m\n\u001b[1;32m 974\u001b[0m method \u001b[38;5;241m=\u001b[39m get_real_method(obj, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mprint_method)\n\u001b[1;32m 976\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 977\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmethod\u001b[49m\u001b[43m(\u001b[49m\u001b[43minclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minclude\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexclude\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexclude\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 978\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 979\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:98\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_mimebundle_\u001b[0;34m(self, include, exclude, **_)\u001b[0m\n\u001b[1;32m 96\u001b[0m include \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(include) \u001b[38;5;28;01mif\u001b[39;00m include \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01melse\u001b[39;00m {\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_jupyter_mimetype}\n\u001b[1;32m 97\u001b[0m include \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m(exclude \u001b[38;5;129;01mor\u001b[39;00m [])\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m {mimetype: \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod_name\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 99\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m mimetype, method_name \u001b[38;5;129;01min\u001b[39;00m MIME_TYPES\u001b[38;5;241m.\u001b[39mitems()\n\u001b[1;32m 100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mimetype \u001b[38;5;129;01min\u001b[39;00m include}\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/jupyter_integration.py:112\u001b[0m, in \u001b[0;36mJupyterIntegration._repr_image_svg_xml\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 110\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_repr_image_svg_xml\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[1;32m 111\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the rendered graph as SVG string.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 112\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpipe\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43msvg\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mSVG_ENCODING\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:104\u001b[0m, in \u001b[0;36mPipe.pipe\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpipe\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 56\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 57\u001b[0m renderer: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 61\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 62\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[1;32m 63\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return the source piped through the Graphviz layout command.\u001b[39;00m\n\u001b[1;32m 64\u001b[0m \n\u001b[1;32m 65\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[38;5;124;03m ' 104\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_legacy\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 105\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 107\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 108\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 109\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 110\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/_tools.py:171\u001b[0m, in \u001b[0;36mdeprecate_positional_args..decorator..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 162\u001b[0m wanted \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mvalue\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m name, value \u001b[38;5;129;01min\u001b[39;00m deprecated\u001b[38;5;241m.\u001b[39mitems())\n\u001b[1;32m 164\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThe signature of \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfunc\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m will be reduced\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 165\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msupported_number\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m positional args\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlist\u001b[39m(supported)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: pass \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mwanted\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 167\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m as keyword arg(s)\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 168\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39mstacklevel,\n\u001b[1;32m 169\u001b[0m category\u001b[38;5;241m=\u001b[39mcategory)\n\u001b[0;32m--> 171\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:121\u001b[0m, in \u001b[0;36mPipe._pipe_legacy\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 112\u001b[0m \u001b[38;5;129m@_tools\u001b[39m\u001b[38;5;241m.\u001b[39mdeprecate_positional_args(supported_number\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m 113\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_pipe_legacy\u001b[39m(\u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 114\u001b[0m \u001b[38;5;28mformat\u001b[39m: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 119\u001b[0m engine: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 120\u001b[0m encoding: typing\u001b[38;5;241m.\u001b[39mOptional[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m typing\u001b[38;5;241m.\u001b[39mUnion[\u001b[38;5;28mbytes\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[0;32m--> 121\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_future\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 122\u001b[0m \u001b[43m \u001b[49m\u001b[43mrenderer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrenderer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 123\u001b[0m \u001b[43m \u001b[49m\u001b[43mformatter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mformatter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 124\u001b[0m \u001b[43m \u001b[49m\u001b[43mneato_no_op\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mneato_no_op\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 125\u001b[0m \u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 126\u001b[0m \u001b[43m \u001b[49m\u001b[43mengine\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 127\u001b[0m \u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/piping.py:149\u001b[0m, in \u001b[0;36mPipe._pipe_future\u001b[0;34m(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)\u001b[0m\n\u001b[1;32m 146\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m encoding \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 147\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(encoding) \u001b[38;5;129;01mis\u001b[39;00m codecs\u001b[38;5;241m.\u001b[39mlookup(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding):\n\u001b[1;32m 148\u001b[0m \u001b[38;5;66;03m# common case: both stdin and stdout need the same encoding\u001b[39;00m\n\u001b[0;32m--> 149\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_pipe_lines_string\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencoding\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencoding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 150\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 151\u001b[0m raw \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pipe_lines(\u001b[38;5;241m*\u001b[39margs, input_encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mencoding, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/piping.py:212\u001b[0m, in \u001b[0;36mpipe_lines_string\u001b[0;34m(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)\u001b[0m\n\u001b[1;32m 206\u001b[0m cmd \u001b[38;5;241m=\u001b[39m dot_command\u001b[38;5;241m.\u001b[39mcommand(engine, \u001b[38;5;28mformat\u001b[39m,\n\u001b[1;32m 207\u001b[0m renderer\u001b[38;5;241m=\u001b[39mrenderer,\n\u001b[1;32m 208\u001b[0m formatter\u001b[38;5;241m=\u001b[39mformatter,\n\u001b[1;32m 209\u001b[0m neato_no_op\u001b[38;5;241m=\u001b[39mneato_no_op)\n\u001b[1;32m 210\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minput_lines\u001b[39m\u001b[38;5;124m'\u001b[39m: input_lines, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mencoding\u001b[39m\u001b[38;5;124m'\u001b[39m: encoding}\n\u001b[0;32m--> 212\u001b[0m proc \u001b[38;5;241m=\u001b[39m \u001b[43mexecute\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_check\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcmd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcapture_output\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquiet\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mquiet\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 213\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\u001b[38;5;241m.\u001b[39mstdout\n", + "File \u001b[0;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/graphviz/backend/execute.py:90\u001b[0m, in \u001b[0;36mrun_check\u001b[0;34m(cmd, input_lines, encoding, quiet, **kwargs)\u001b[0m\n\u001b[1;32m 88\u001b[0m proc\u001b[38;5;241m.\u001b[39mcheck_returncode()\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m subprocess\u001b[38;5;241m.\u001b[39mCalledProcessError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(\u001b[38;5;241m*\u001b[39me\u001b[38;5;241m.\u001b[39margs)\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proc\n", + "\u001b[0;31mCalledProcessError\u001b[0m: Command '[PosixPath('dot'), '-Kneato', '-Tsvg']' died with . [stderr: 'double free or corruption (!prev)\\n']" + ] + }, { "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Structural Graph\n", - "\n", - "\n", - "\n", - "0\n", - "\n", - "AP3\n", - "\n", - "\n", - "\n", - "0->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13\n", - "\n", - "PI\n", - "\n", - "\n", - "\n", - "0->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1\n", - "\n", - "UFO\n", - "\n", - "\n", - "\n", - "1->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "1->1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "2\n", - "\n", - "FUL\n", - "\n", - "\n", - "\n", - "3\n", - "\n", - "FT\n", - "\n", - "\n", - "\n", - "4\n", - "\n", - "AP1\n", - "\n", - "\n", - "\n", - "3->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9\n", - "\n", - "AG\n", - "\n", - "\n", - "\n", - "4->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12\n", - "\n", - "TFL1\n", - "\n", - "\n", - "\n", - "4->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "4->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5\n", - "\n", - "EMF1\n", - "\n", - "\n", - "\n", - "5->3\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6\n", - "\n", - "LFY\n", - "\n", - "\n", - "\n", - "5->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "5->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->5\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->12\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "6->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14\n", - "\n", - "SEP\n", - "\n", - "\n", - "\n", - "6->14\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "7\n", - "\n", - "AP2\n", - "\n", - "\n", - "\n", - "7->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8\n", - "\n", - "WUS\n", - "\n", - "\n", - "\n", - "8->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "8->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "9->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "10\n", - "\n", - "LUG\n", - "\n", - "\n", - "\n", - "10->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "11\n", - "\n", - "CLF\n", - "\n", - "\n", - "\n", - "11->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->2\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->4\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->6\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->7\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "12->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "13->13\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->8\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->9\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "14->13\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1318,7 +668,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Control - State Transition Graph.ipynb b/tutorials/Control - State Transition Graph.ipynb index c80b511..9640acd 100644 --- a/tutorials/Control - State Transition Graph.ipynb +++ b/tutorials/Control - State Transition Graph.ipynb @@ -20,7 +20,9 @@ "metadata": {}, "outputs": [], "source": [ - "%matplotlib inline" + "import graphviz\n", + "#\n", + "from cana.datasets.bio import MARQUESPITA" ] }, { @@ -29,12 +31,7 @@ "metadata": {}, "outputs": [], "source": [ - "import networkx as nx\n", - "import graphviz\n", - "import matplotlib.pyplot as plt\n", - "#\n", - "import cana\n", - "from cana.datasets.bio import MARQUESPITA" + "%matplotlib inline" ] }, { @@ -47,13 +44,13 @@ "output_type": "stream", "text": [ "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" ] } ], @@ -77,7 +74,8 @@ "text": [ "[(0, {'label': '1111110'}), (1, {'label': '1111111'})]\n", "STG: [[0]]\n", - "BNS: [[126]]\n" + "'BNS' could not be found! You must have it compiled or download the binary for your system from the 'bns' website (https://people.kth.se/~dubrova/bns.html).\n", + "BNS: []\n" ] } ], @@ -110,7 +108,7 @@ "\n", "\n", - "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -199,7 +197,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Control - Thaliana.ipynb b/tutorials/Control - Thaliana.ipynb index be696f5..9e85060 100644 --- a/tutorials/Control - Thaliana.ipynb +++ b/tutorials/Control - Thaliana.ipynb @@ -14,9 +14,11 @@ "metadata": {}, "outputs": [], "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "%matplotlib inline" + "from __future__ import division\n", + "from itertools import product\n", + "from cana.datasets.bio import THALIANA\n", + "from IPython.display import display\n", + "from IPython.core.display import HTML" ] }, { @@ -25,13 +27,9 @@ "metadata": {}, "outputs": [], "source": [ - "from __future__ import division\n", - "import numpy as np\n", - "from itertools import product\n", - "from cana.control import fvs, mds, sc\n", - "from cana.datasets.bio import THALIANA\n", - "from IPython.display import display\n", - "from IPython.core.display import HTML" + "%load_ext autoreload\n", + "%autoreload 2\n", + "%matplotlib inline" ] }, { @@ -74,27 +72,11 @@ "output_type": "stream", "text": [ "Trying with 1 Driver Nodes\n", - "Trying with 2 Driver Nodes\n" - ] - }, - { - "ename": "KeyboardInterrupt", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mHTML\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'

Control State Transition Graph (CSTG)

'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# THIS MIGHT TAKE A LONG TIME, it is here for demo purposes.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mdriver_nodes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattractor_driver_nodes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmin_dvs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmax_dvs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mverbose\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_node_name\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdriver_nodes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m#> ['AP2', 'EMF1', 'LFY', 'TFL1', 'UFO', 'WUS'], ['AG', 'EMF1', 'LFY', 'TFL1', 'UFO', 'WUS']\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Sites/CANA/cana/boolean_network.py\u001b[0m in \u001b[0;36mattractor_driver_nodes\u001b[0;34m(self, min_dvs, max_dvs, verbose)\u001b[0m\n\u001b[1;32m 814\u001b[0m \u001b[0mdvs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdvs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 815\u001b[0m \u001b[0;31m# cstg = self.controlled_state_transition_graph(dvs)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 816\u001b[0;31m \u001b[0mcag\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontrolled_attractor_graph\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdvs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 817\u001b[0m \u001b[0matt_reachable_from\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmean_reachable_attractors\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcag\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 818\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/Sites/CANA/cana/boolean_network.py\u001b[0m in \u001b[0;36mcontrolled_attractor_graph\u001b[0;34m(self, driver_nodes)\u001b[0m\n\u001b[1;32m 947\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 948\u001b[0m \u001b[0mattractor_states\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0ms\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0matt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_attractors\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[0;32min\u001b[0m \u001b[0matt\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 949\u001b[0;31m \u001b[0mcstg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 950\u001b[0m \u001b[0mcstg\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'C-'\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mcstg\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m' Att('\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m','\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnodes\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdv\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mdv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdriver_nodes\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m')'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 951\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 178\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 179\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 180\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_reconstruct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mrv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 181\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 182\u001b[0m \u001b[0;31m# If is its own copy, don't memoize.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36m_reconstruct\u001b[0;34m(x, memo, func, args, state, listiter, dictiter, deepcopy)\u001b[0m\n\u001b[1;32m 279\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mstate\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 280\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdeep\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 281\u001b[0;31m \u001b[0mstate\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstate\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 282\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'__setstate__'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 283\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__setstate__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[0mcopier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deepcopy_dispatch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 149\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 150\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopier\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 151\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36m_deepcopy_dict\u001b[0;34m(x, memo, deepcopy)\u001b[0m\n\u001b[1;32m 239\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 240\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 241\u001b[0;31m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 242\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 243\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdict\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deepcopy_dict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[0mcopier\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deepcopy_dispatch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 149\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcopier\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 150\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopier\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 151\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36m_deepcopy_dict\u001b[0;34m(x, memo, deepcopy)\u001b[0m\n\u001b[1;32m 239\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 240\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 241\u001b[0;31m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdeepcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 242\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 243\u001b[0m \u001b[0md\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdict\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_deepcopy_dict\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/anaconda3/lib/python3.7/copy.py\u001b[0m in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 140\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 141\u001b[0m \u001b[0md\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 142\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmemo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_nil\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 143\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0my\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0m_nil\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 144\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + "Trying with 2 Driver Nodes\n", + "Trying with 3 Driver Nodes\n", + "Trying with 4 Driver Nodes\n", + "Trying with 5 Driver Nodes\n", + "Trying with 6 Driver Nodes\n" ] } ], @@ -108,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -139,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -170,7 +152,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -204,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -221,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -268,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -278,7 +260,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "scrolled": true }, @@ -455,7 +437,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "scrolled": true }, @@ -607,7 +589,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Dynamics Canalization Map - Breast Cancer.ipynb b/tutorials/Dynamics Canalization Map - Breast Cancer.ipynb index 1571c52..0b06d9c 100644 --- a/tutorials/Dynamics Canalization Map - Breast Cancer.ipynb +++ b/tutorials/Dynamics Canalization Map - Breast Cancer.ipynb @@ -24,7 +24,6 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "from cana.datasets.bio import BREAST_CANCER\n", "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz\n", "from IPython.display import display" @@ -44,44 +43,44 @@ "execution_count": 4, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "var-2-out-0 {'label': 'IGF1R_2', 'type': 'variable', 'mode': 'output', 'value': 0, 'constant': False, 'group': 2}\n", - "var-2-out-1 {'label': 'IGF1R_2', 'type': 'variable', 'mode': 'output', 'value': 1, 'constant': False, 'group': 2}\n", - "thr-0-var-2-out-0 {'label': '2', 'type': 'threshold', 'tau': 2, 'group': 2}\n", - "var-0-out-0 {'label': 'IGF1R_T', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", - "fus-0-thr-0-var-2-out-0 {'type': 'fusion', 'group': 2}\n", - "var-10-out-0 {'label': 'HER2', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", - "var-42-out-0 {'label': 'FOXO3', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", - "thr-1-var-2-out-0 {'label': '1', 'type': 'threshold', 'tau': 1, 'group': 2}\n", - "var-50-out-1 {'label': 'S6K', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", - "thr-2-var-2-out-0 {'label': '1', 'type': 'threshold', 'tau': 1, 'group': 2}\n", - "var-1-out-0 {'label': 'IGF1R', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", - "thr-3-var-2-out-1 {'label': '3', 'type': 'threshold', 'tau': 3, 'group': 2}\n", - "var-0-out-1 {'label': 'IGF1R_T', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", - "var-1-out-1 {'label': 'IGF1R', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", - "var-50-out-0 {'label': 'S6K', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", - "thr-4-var-2-out-1 {'label': '4', 'type': 'threshold', 'tau': 4, 'group': 2}\n", - "var-10-out-1 {'label': 'HER2', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", - "var-42-out-1 {'label': 'FOXO3', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n" - ] - }, { "name": "stderr", "output_type": "stream", "text": [ "Warning: node 'var-2-out-0', graph '%3' size too small for label\n", "Warning: node 'var-2-out-1', graph '%3' size too small for label\n", + "Warning: node 'var-1-out-0', graph '%3' size too small for label\n", "Warning: node 'var-0-out-0', graph '%3' size too small for label\n", "Warning: node 'var-10-out-0', graph '%3' size too small for label\n", "Warning: node 'var-42-out-0', graph '%3' size too small for label\n", - "Warning: node 'var-1-out-0', graph '%3' size too small for label\n", - "Warning: node 'var-0-out-1', graph '%3' size too small for label\n", "Warning: node 'var-1-out-1', graph '%3' size too small for label\n", "Warning: node 'var-10-out-1', graph '%3' size too small for label\n", - "Warning: node 'var-42-out-1', graph '%3' size too small for label\n" + "Warning: node 'var-42-out-1', graph '%3' size too small for label\n", + "Warning: node 'var-0-out-1', graph '%3' size too small for label\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "var-2-out-0 {'label': 'IGF1R_2', 'type': 'variable', 'mode': 'output', 'value': 0, 'constant': False, 'group': 2}\n", + "var-2-out-1 {'label': 'IGF1R_2', 'type': 'variable', 'mode': 'output', 'value': 1, 'constant': False, 'group': 2}\n", + "thr-0-var-2-out-0 {'label': '1', 'type': 'threshold', 'tau': 1, 'group': 2}\n", + "var-1-out-0 {'label': 'IGF1R', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", + "thr-1-var-2-out-0 {'label': '1', 'type': 'threshold', 'tau': 1, 'group': 2}\n", + "var-50-out-1 {'label': 'S6K', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", + "thr-2-var-2-out-0 {'label': '2', 'type': 'threshold', 'tau': 2, 'group': 2}\n", + "var-0-out-0 {'label': 'IGF1R_T', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", + "fus-0-thr-2-var-2-out-0 {'type': 'fusion', 'group': 2}\n", + "var-10-out-0 {'label': 'HER2', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", + "var-42-out-0 {'label': 'FOXO3', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", + "thr-3-var-2-out-1 {'label': '4', 'type': 'threshold', 'tau': 4, 'group': 2}\n", + "var-1-out-1 {'label': 'IGF1R', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", + "var-10-out-1 {'label': 'HER2', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", + "var-42-out-1 {'label': 'FOXO3', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n", + "var-50-out-0 {'label': 'S6K', 'type': 'variable', 'mode': 'input', 'value': 0, 'group': 2}\n", + "thr-4-var-2-out-1 {'label': '3', 'type': 'threshold', 'tau': 3, 'group': 2}\n", + "var-0-out-1 {'label': 'IGF1R_T', 'type': 'variable', 'mode': 'input', 'value': 1, 'group': 2}\n" ] }, { @@ -90,231 +89,232 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-2-out-0\n", - "\n", - "IGF1R_2\n", + "\n", + "IGF1R_2\n", "\n", "\n", "\n", "var-2-out-1\n", - "\n", - "IGF1R_2\n", + "\n", + "IGF1R_2\n", "\n", "\n", "\n", "thr-0-var-2-out-0\n", - "\n", - "2\n", + "\n", + "1\n", "\n", "\n", "\n", "thr-0-var-2-out-0->var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-0-out-0\n", - "\n", - "IGF1R_T\n", + "var-1-out-0\n", + "\n", + "IGF1R\n", "\n", - "\n", + "\n", "\n", - "var-0-out-0->thr-0-var-2-out-0\n", - "\n", - "\n", + "var-1-out-0->thr-0-var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-0-var-2-out-0\n", - "\n", + "thr-1-var-2-out-0\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-0-var-2-out-0->thr-0-var-2-out-0\n", - "\n", - "\n", + "thr-1-var-2-out-0->var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-10-out-0\n", - "\n", - "HER2\n", + "var-50-out-1\n", + "\n", + "S6K\n", "\n", - "\n", + "\n", "\n", - "var-10-out-0->fus-0-thr-0-var-2-out-0\n", - "\n", + "var-50-out-1->thr-1-var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-42-out-0\n", - "\n", - "FOXO3\n", + "thr-2-var-2-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-42-out-0->fus-0-thr-0-var-2-out-0\n", - "\n", + "thr-2-var-2-out-0->var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "thr-1-var-2-out-0\n", - "\n", - "1\n", + "var-0-out-0\n", + "\n", + "IGF1R_T\n", "\n", - "\n", + "\n", "\n", - "thr-1-var-2-out-0->var-2-out-0\n", - "\n", - "\n", + "var-0-out-0->thr-2-var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-50-out-1\n", - "\n", - "S6K\n", + "fus-0-thr-2-var-2-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-50-out-1->thr-1-var-2-out-0\n", - "\n", - "\n", + "fus-0-thr-2-var-2-out-0->thr-2-var-2-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "thr-2-var-2-out-0\n", - "\n", - "1\n", + "var-10-out-0\n", + "\n", + "HER2\n", "\n", - "\n", + "\n", "\n", - "thr-2-var-2-out-0->var-2-out-0\n", - "\n", - "\n", + "var-10-out-0->fus-0-thr-2-var-2-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0\n", - "\n", - "IGF1R\n", + "var-42-out-0\n", + "\n", + "FOXO3\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->thr-2-var-2-out-0\n", - "\n", - "\n", + "var-42-out-0->fus-0-thr-2-var-2-out-0\n", + "\n", "\n", "\n", "\n", "thr-3-var-2-out-1\n", - "\n", - "3\n", + "\n", + "4\n", "\n", "\n", "\n", "thr-3-var-2-out-1->var-2-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-1\n", - "\n", - "IGF1R_T\n", - "\n", - "\n", - "\n", - "var-0-out-1->thr-3-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-1\n", - "\n", - "IGF1R\n", + "\n", + "IGF1R\n", "\n", "\n", - "\n", + "\n", "var-1-out-1->thr-3-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-2-out-1\n", - "\n", - "4\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-1-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "var-10-out-1\n", + "\n", + "HER2\n", + "\n", + "\n", + "\n", + "var-10-out-1->thr-3-var-2-out-1\n", + "\n", + "\n", + "\n", + "\n", "\n", + "var-42-out-1\n", + "\n", + "FOXO3\n", + "\n", + "\n", + "\n", + "var-42-out-1->thr-3-var-2-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", "var-50-out-0\n", - "\n", - "S6K\n", + "\n", + "S6K\n", "\n", "\n", - "\n", + "\n", "var-50-out-0->thr-3-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-50-out-0->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", - "thr-4-var-2-out-1->var-2-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-10-out-1\n", - "\n", - "HER2\n", - "\n", - "\n", "\n", - "var-10-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "thr-4-var-2-out-1->var-2-out-1\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-42-out-1\n", - "\n", - "FOXO3\n", + "var-0-out-1\n", + "\n", + "IGF1R_T\n", "\n", - "\n", + "\n", "\n", - "var-42-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "var-0-out-1->thr-4-var-2-out-1\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -350,9 +350,9 @@ "Warning: node 'var-2-out-0', graph '%3' size too small for label\n", "Warning: node 'var-10-out-0', graph '%3' size too small for label\n", "Warning: node 'var-42-out-0', graph '%3' size too small for label\n", - "Warning: node 'var-2-out-1', graph '%3' size too small for label\n", "Warning: node 'var-10-out-1', graph '%3' size too small for label\n", "Warning: node 'var-42-out-1', graph '%3' size too small for label\n", + "Warning: node 'var-2-out-1', graph '%3' size too small for label\n", "Warning: node 'var-3-out-0', graph '%3' size too small for label\n", "Warning: node 'var-3-out-1', graph '%3' size too small for label\n", "Warning: node 'var-4-out-0', graph '%3' size too small for label\n", @@ -485,6247 +485,6176 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-0-out-0\n", - "\n", - "IGF1R_T\n", + "\n", + "IGF1R_T\n", "\n", "\n", "\n", "var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-1-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-0-out-0->thr-0-var-1-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-2-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-2-var-2-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-0-out-0->thr-0-var-2-out-0\n", - "\n", - "\n", + "var-0-out-0->thr-2-var-2-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-0-out-1\n", - "\n", - "IGF1R_T\n", + "\n", + "IGF1R_T\n", "\n", "\n", "\n", "var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-1-var-1-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-1-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-0-out-1->fus-0-thr-1-var-1-out-1\n", - "\n", + "var-0-out-1->fus-0-thr-2-var-1-out-1\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-2-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-4-var-2-out-1\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-0-out-1->thr-3-var-2-out-1\n", - "\n", - "\n", + "var-0-out-1->thr-4-var-2-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-1-out-0\n", - "\n", - "IGF1R\n", + "\n", + "IGF1R\n", "\n", "\n", "\n", "var-2-out-0\n", - "\n", - "IGF1R_2\n", + "\n", + "IGF1R_2\n", "\n", "\n", "\n", "var-1-out-0->var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-21-out-0\n", - "\n", - "6\n", + "\n", + "6\n", "\n", "\n", "\n", "var-1-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-26-out-0\n", - "\n", - "8\n", + "\n", + "\n", + "thr-0-var-26-out-0\n", + "\n", + "8\n", "\n", - "\n", + "\n", "\n", - "var-1-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-1-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-1-out-1\n", - "\n", - "IGF1R\n", + "\n", + "IGF1R\n", + "\n", + "\n", + "\n", + "thr-3-var-2-out-1\n", + "\n", + "4\n", "\n", "\n", "\n", "var-1-out-1->thr-3-var-2-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-4-var-2-out-1\n", - "\n", - "4\n", + "\n", + "\n", "\n", "\n", "\n", "var-1-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-1-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-26-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-26-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-1-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", + "var-1-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", "\n", "thr-0-var-1-out-0->var-1-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-2-out-0->thr-0-var-1-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-2-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-2-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-2-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-1-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-1-out-0->thr-0-var-1-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-10-out-0\n", - "\n", - "HER2\n", + "\n", + "HER2\n", "\n", "\n", "\n", "var-10-out-0->fus-0-thr-0-var-1-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-10-out-0->var-10-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-2-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-2-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-10-out-0->fus-0-thr-0-var-2-out-0\n", - "\n", + "var-10-out-0->fus-0-thr-2-var-2-out-0\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-19-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-2-var-19-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-10-out-0->thr-1-var-19-out-0\n", - "\n", - "\n", + "var-10-out-0->thr-2-var-19-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-20-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-20-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-10-out-0->fus-0-thr-0-var-20-out-0\n", - "\n", + "var-10-out-0->fus-0-thr-2-var-20-out-0\n", + "\n", "\n", "\n", "\n", "var-42-out-0\n", - "\n", - "FOXO3\n", + "\n", + "FOXO3\n", "\n", "\n", "\n", "var-42-out-0->fus-0-thr-0-var-1-out-0\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-42-out-0->fus-0-thr-0-var-2-out-0\n", - "\n", + "var-42-out-0->fus-0-thr-2-var-2-out-0\n", + "\n", "\n", "\n", "\n", "thr-0-var-12-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-42-out-0->thr-0-var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-42-out-0->fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-34-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-42-out-0->thr-0-var-34-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-46-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-42-out-0->thr-0-var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-53-out-0\n", - "\n", - "3\n", + "\n", + "\n", + "thr-0-var-53-out-0\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-42-out-0->thr-1-var-53-out-0\n", - "\n", - "\n", + "var-42-out-0->thr-0-var-53-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-54-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-54-out-0\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-42-out-0->fus-0-thr-0-var-54-out-0\n", - "\n", + "var-42-out-0->fus-0-thr-1-var-54-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-55-out-0\n", - "\n", - "FOXA1\n", + "\n", + "FOXA1\n", "\n", "\n", "\n", "var-42-out-0->var-55-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-1-out-1\n", - "\n", - "1\n", + "\n", + "2\n", "\n", "\n", "\n", "thr-1-var-1-out-1->var-1-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-1-var-1-out-1->thr-1-var-1-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-2-out-1\n", - "\n", - "IGF1R_2\n", - "\n", - "\n", - "\n", - "var-2-out-1->fus-0-thr-1-var-1-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-2-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-2-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-1-out-1\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "thr-2-var-1-out-1->var-1-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-10-out-1\n", - "\n", - "HER2\n", + "\n", + "HER2\n", "\n", - "\n", - "\n", - "var-10-out-1->thr-2-var-1-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-10-out-1->thr-1-var-1-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-10-out-1->var-10-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-10-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-10-out-1->thr-3-var-2-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "thr-3-var-19-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-10-out-1->thr-3-var-19-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-4-var-20-out-1\n", - "\n", - "5\n", + "\n", + "5\n", "\n", "\n", - "\n", + "\n", "var-10-out-1->thr-4-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-5-var-20-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-10-out-1->thr-5-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-42-out-1\n", - "\n", - "FOXO3\n", + "\n", + "FOXO3\n", "\n", - "\n", - "\n", - "var-42-out-1->thr-2-var-1-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-42-out-1->thr-1-var-1-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-42-out-1->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-42-out-1->thr-3-var-2-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-1-var-12-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->fus-0-thr-1-var-12-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "thr-1-var-13-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->thr-1-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-34-out-1\n", - "\n", - "p21_p27_T\n", + "\n", + "p21_p27_T\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->var-34-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-46-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-46-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-42-out-1->thr-2-var-46-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-42-out-1->thr-3-var-46-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-53-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->fus-0-thr-2-var-53-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-54-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->thr-2-var-54-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-55-out-1\n", - "\n", - "FOXA1\n", + "\n", + "FOXA1\n", "\n", "\n", - "\n", + "\n", "var-42-out-1->var-55-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-2-out-0->var-2-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-2-out-0->thr-0-var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", + "thr-2-var-1-out-1\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "thr-2-var-1-out-1->var-1-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-2-var-1-out-1->thr-2-var-1-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "var-2-out-1\n", + "\n", + "IGF1R_2\n", + "\n", + "\n", + "\n", + "var-2-out-1->fus-0-thr-2-var-1-out-1\n", + "\n", + "\n", + "\n", + "\n", + "var-2-out-1->fus-0-thr-1-var-21-out-1\n", + "\n", + "\n", + "\n", + "\n", + "var-2-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-50-out-1\n", - "\n", - "S6K\n", + "\n", + "S6K\n", "\n", "\n", - "\n", + "\n", "var-50-out-1->var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-51-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-50-out-1->thr-1-var-51-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-2-var-2-out-0->var-2-out-0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-2-var-2-out-0->thr-2-var-2-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "thr-3-var-2-out-1->var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-50-out-0\n", - "\n", - "S6K\n", + "\n", + "S6K\n", "\n", "\n", "\n", "var-50-out-0->thr-3-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-50-out-0->thr-4-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-51-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-50-out-0->fus-0-thr-0-var-51-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "thr-4-var-2-out-1->var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-3-out-0\n", - "\n", - "Fulvestrant\n", + "\n", + "Fulvestrant\n", "\n", "\n", "\n", "var-3-out-0->var-3-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-53-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-3-out-0->thr-2-var-53-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-3-out-0->thr-2-var-54-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-3-out-1\n", - "\n", - "Fulvestrant\n", + "\n", + "Fulvestrant\n", "\n", "\n", "\n", "var-3-out-1->var-3-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-0-var-53-out-0\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "var-3-out-1->thr-0-var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-0\n", - "\n", - "ESR1_2\n", + "\n", + "ESR1_2\n", "\n", "\n", "\n", "var-3-out-1->var-54-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-1-var-53-out-0\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "var-3-out-1->thr-1-var-53-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-4-out-0\n", - "\n", - "Alpelisib\n", + "\n", + "Alpelisib\n", "\n", "\n", "\n", "var-4-out-0->var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-26-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-26-out-1\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-4-out-0->thr-2-var-26-out-1\n", - "\n", - "\n", + "var-4-out-0->thr-3-var-26-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-27-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-4-out-0->thr-2-var-27-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-4-out-1\n", - "\n", - "Alpelisib\n", + "\n", + "Alpelisib\n", "\n", "\n", "\n", "var-4-out-1->var-4-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-0-var-26-out-0\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "var-4-out-1->thr-0-var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-0\n", - "\n", - "PI3K_2\n", + "\n", + "PI3K_2\n", "\n", "\n", "\n", "var-4-out-1->var-27-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-1-var-26-out-0\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "var-4-out-1->thr-1-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-5-out-0\n", - "\n", - "Everolimus\n", + "\n", + "Everolimus\n", "\n", "\n", "\n", "var-5-out-0->var-5-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-2-var-15-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-5-out-0->thr-2-var-15-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-32-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-5-out-0->thr-2-var-32-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-41-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-5-out-0->thr-2-var-41-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-5-out-1\n", - "\n", - "Everolimus\n", + "\n", + "Everolimus\n", "\n", "\n", "\n", "var-5-out-1->var-5-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-15-out-0\n", - "\n", - "mTORC2\n", + "\n", + "mTORC2\n", "\n", "\n", "\n", "var-5-out-1->var-15-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-32-out-0\n", - "\n", - "mTORC2_pm\n", + "\n", + "mTORC2_pm\n", "\n", "\n", "\n", "var-5-out-1->var-32-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-41-out-0\n", - "\n", - "mTORC1\n", + "\n", + "mTORC1\n", "\n", "\n", "\n", "var-5-out-1->var-41-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-6-out-0\n", - "\n", - "Trametinib\n", + "\n", + "Trametinib\n", "\n", "\n", "\n", "var-6-out-0->var-6-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-24-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-4-var-24-out-1\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-6-out-0->thr-3-var-24-out-1\n", - "\n", - "\n", + "var-6-out-0->thr-4-var-24-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-4-var-25-out-1\n", - "\n", - "4\n", + "\n", + "\n", + "thr-5-var-25-out-1\n", + "\n", + "4\n", "\n", - "\n", + "\n", "\n", - "var-6-out-0->thr-4-var-25-out-1\n", - "\n", - "\n", + "var-6-out-0->thr-5-var-25-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-6-out-1\n", - "\n", - "Trametinib\n", + "\n", + "Trametinib\n", "\n", "\n", "\n", "var-6-out-1->var-6-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-24-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-6-out-1->thr-0-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-25-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-25-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-6-out-1->thr-2-var-25-out-0\n", - "\n", - "\n", + "var-6-out-1->thr-3-var-25-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-7-out-0\n", - "\n", - "Ipatasertib\n", + "\n", + "Ipatasertib\n", "\n", "\n", "\n", "var-7-out-0->var-7-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-33-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-4-var-33-out-1\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-7-out-0->thr-3-var-33-out-1\n", - "\n", - "\n", + "var-7-out-0->thr-4-var-33-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-7-out-1\n", - "\n", - "Ipatasertib\n", + "\n", + "Ipatasertib\n", "\n", "\n", "\n", "var-7-out-1->var-7-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-33-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-0-var-33-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-7-out-1->thr-1-var-33-out-0\n", - "\n", - "\n", + "var-7-out-1->thr-0-var-33-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-8-out-0\n", - "\n", - "Palbociclib\n", + "\n", + "Palbociclib\n", "\n", "\n", "\n", "var-8-out-0->var-8-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-64-out-1\n", - "\n", - "CDK46\n", + "\n", + "CDK46\n", "\n", "\n", "\n", "var-8-out-0->var-64-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-8-out-1\n", - "\n", - "Palbociclib\n", + "\n", + "Palbociclib\n", "\n", "\n", "\n", "var-8-out-1->var-8-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-64-out-0\n", - "\n", - "CDK46\n", + "\n", + "CDK46\n", "\n", "\n", "\n", "var-8-out-1->var-64-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-9-out-0\n", - "\n", - "Neratinib\n", + "\n", + "Neratinib\n", "\n", "\n", "\n", "var-9-out-0->var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-9-out-0->thr-3-var-19-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-9-out-0->thr-4-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-9-out-0->thr-5-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-9-out-1\n", - "\n", - "Neratinib\n", + "\n", + "Neratinib\n", "\n", "\n", "\n", "var-9-out-1->var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-0-var-19-out-0\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "var-9-out-1->thr-0-var-19-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0\n", - "\n", - "HER2_3_2\n", + "\n", + "HER2_3_2\n", "\n", "\n", "\n", "var-9-out-1->var-20-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-19-out-0\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "var-9-out-1->thr-2-var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-11-out-0\n", - "\n", - "HER3_T\n", + "\n", + "HER3_T\n", "\n", "\n", "\n", "var-11-out-0->var-11-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-11-out-0->thr-0-var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-11-out-1\n", - "\n", - "HER3_T\n", + "\n", + "HER3_T\n", "\n", "\n", "\n", "var-11-out-1->var-11-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-11-out-1->fus-0-thr-1-var-12-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-12-out-0\n", - "\n", - "HER3\n", + "\n", + "HER3\n", "\n", "\n", "\n", "var-12-out-0->fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-19-out-0\n", - "\n", - "3\n", + "\n", + "\n", + "thr-1-var-19-out-0\n", + "\n", + "3\n", "\n", - "\n", + "\n", "\n", - "var-12-out-0->thr-0-var-19-out-0\n", - "\n", - "\n", + "var-12-out-0->thr-1-var-19-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-20-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-0-var-20-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-12-out-0->thr-2-var-20-out-0\n", - "\n", - "\n", + "var-12-out-0->thr-0-var-20-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-12-out-1\n", - "\n", - "HER3\n", + "\n", + "HER3\n", "\n", "\n", "\n", "var-12-out-1->thr-1-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-3-var-19-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-12-out-1->fus-0-thr-3-var-19-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-12-out-1->thr-4-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-12-out-0->var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-13-out-0\n", - "\n", - "HER3_2\n", + "\n", + "HER3_2\n", "\n", "\n", "\n", "var-13-out-0->thr-0-var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-13-out-0->thr-0-var-19-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-1-var-20-out-0\n", - "\n", - "2\n", + "var-13-out-0->thr-1-var-19-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-13-out-0->thr-1-var-20-out-0\n", - "\n", - "\n", + "var-13-out-0->thr-0-var-20-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "thr-3-var-20-out-0\n", + "\n", + "2\n", + "\n", + "\n", "\n", - "var-13-out-0->thr-2-var-20-out-0\n", - "\n", - "\n", + "var-13-out-0->thr-3-var-20-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-12-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", "\n", "thr-1-var-12-out-1->var-12-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-1-var-12-out-1->thr-1-var-12-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-13-out-1\n", - "\n", - "HER3_2\n", + "\n", + "HER3_2\n", "\n", "\n", "\n", "var-13-out-1->fus-0-thr-1-var-12-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-13-out-1->fus-0-thr-3-var-19-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-13-out-1->thr-5-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-13-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", "\n", "thr-0-var-13-out-0->var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-13-out-0->thr-0-var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-13-out-1->var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-14-out-0\n", - "\n", - "PDK1\n", + "\n", + "PDK1\n", "\n", "\n", "\n", "var-14-out-0->var-14-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-17-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-14-out-0->fus-0-thr-0-var-17-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-14-out-1\n", - "\n", - "PDK1\n", + "\n", + "PDK1\n", "\n", "\n", "\n", "var-14-out-1->var-14-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-17-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-14-out-1->thr-1-var-17-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-15-out-0->var-15-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-15-out-0->fus-0-thr-0-var-17-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-15-out-1\n", - "\n", - "mTORC2\n", + "\n", + "mTORC2\n", "\n", "\n", "\n", "var-15-out-1->thr-2-var-15-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-15-out-1->thr-1-var-17-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-2-var-15-out-1->var-15-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-16-out-0\n", - "\n", - "SGK1_T\n", + "\n", + "SGK1_T\n", "\n", "\n", "\n", "var-16-out-0->var-16-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-16-out-0->fus-0-thr-0-var-17-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-16-out-1\n", - "\n", - "SGK1_T\n", + "\n", + "SGK1_T\n", "\n", "\n", "\n", "var-16-out-1->var-16-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-16-out-1->thr-1-var-17-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-17-out-0\n", - "\n", - "SGK1\n", + "\n", + "SGK1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-39-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-17-out-0->thr-1-var-39-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-42-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", "\n", "var-17-out-0->thr-1-var-42-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-17-out-1\n", - "\n", - "SGK1\n", + "\n", + "SGK1\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-39-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-17-out-1->fus-0-thr-0-var-39-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-42-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-17-out-1->fus-0-thr-0-var-42-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "thr-0-var-17-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", "\n", "thr-0-var-17-out-0->var-17-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-17-out-0->thr-0-var-17-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-17-out-1->var-17-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-18-out-0\n", - "\n", - "PIM\n", + "\n", + "PIM\n", "\n", "\n", "\n", "var-18-out-0->var-18-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-35-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-18-out-0->thr-2-var-35-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-40-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-18-out-0->thr-1-var-40-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-18-out-0->thr-1-var-42-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-47-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", "\n", "var-18-out-0->thr-1-var-47-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-18-out-1\n", - "\n", - "PIM\n", + "\n", + "PIM\n", "\n", "\n", "\n", "var-18-out-1->var-18-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-35-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-18-out-1->fus-0-thr-0-var-35-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-40-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-18-out-1->fus-0-thr-0-var-40-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-18-out-1->fus-0-thr-0-var-42-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-47-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-18-out-1->fus-0-thr-0-var-47-out-1\n", - "\n", + "\n", "\n", "\n", "\n", "var-19-out-0\n", - "\n", - "HER2_3\n", + "\n", + "HER2_3\n", "\n", - "\n", + "\n", "\n", - "var-19-out-0->fus-0-thr-0-var-20-out-0\n", - "\n", + "var-19-out-0->fus-0-thr-2-var-20-out-0\n", + "\n", "\n", "\n", "\n", "var-19-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-22-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-19-out-0->thr-1-var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-19-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-19-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-19-out-1\n", - "\n", - "HER2_3\n", + "\n", + "HER2_3\n", "\n", "\n", "\n", "var-19-out-1->thr-4-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-19-out-1->thr-5-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-19-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-2-var-22-out-1\n", - "\n", + "fus-0-thr-3-var-22-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-19-out-1->fus-0-thr-2-var-22-out-1\n", - "\n", + "var-19-out-1->fus-0-thr-3-var-22-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-19-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", + "var-19-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", "\n", "thr-0-var-19-out-0->var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-0-var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-1-var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-2-var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-1-var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-0-var-23-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->fus-0-thr-0-var-23-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-0-var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-27-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-20-out-0->fus-0-thr-0-var-27-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "thr-1-var-19-out-0->var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-2-var-19-out-0->var-19-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-3-var-19-out-1->var-19-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "fus-0-thr-3-var-19-out-1->thr-3-var-19-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-1\n", - "\n", - "HER2_3_2\n", + "\n", + "HER2_3_2\n", "\n", "\n", "\n", "var-20-out-1->var-19-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-20-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-20-out-1->fus-0-thr-2-var-22-out-1\n", - "\n", + "var-20-out-1->fus-0-thr-3-var-22-out-1\n", + "\n", "\n", "\n", "\n", "thr-1-var-23-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", "\n", "var-20-out-1->thr-1-var-23-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-3-var-26-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-26-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-20-out-1->fus-0-thr-3-var-26-out-1\n", - "\n", + "var-20-out-1->fus-0-thr-2-var-26-out-1\n", + "\n", "\n", "\n", "\n", "var-20-out-1->thr-2-var-27-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-0-var-20-out-0\n", - "\n", - "1\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-20-out-0->var-20-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-2-var-20-out-0\n", + "\n", + "1\n", "\n", - "\n", + "\n", "\n", - "fus-0-thr-0-var-20-out-0->thr-0-var-20-out-0\n", - "\n", - "\n", + "thr-2-var-20-out-0->var-20-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "thr-1-var-20-out-0->var-20-out-0\n", - "\n", - "\n", + "fus-0-thr-2-var-20-out-0->thr-2-var-20-out-0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-20-out-0->var-20-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-25-out-1\n", - "\n", - "MAPK_2\n", + "\n", + "MAPK_2\n", "\n", - "\n", - "\n", - "var-25-out-1->thr-1-var-20-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-25-out-1->thr-3-var-20-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-24-out-1\n", - "\n", - "MAPK\n", + "\n", + "MAPK\n", "\n", "\n", - "\n", + "\n", "var-25-out-1->var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-25-out-1->fus-0-thr-0-var-39-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-43-out-1\n", - "\n", - "FOXO3_Ub\n", + "\n", + "FOXO3_Ub\n", "\n", "\n", - "\n", + "\n", "var-25-out-1->var-43-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-46-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-25-out-1->thr-1-var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-25-out-1->fus-0-thr-0-var-47-out-1\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-20-out-0->var-20-out-0\n", - "\n", - "\n", + "\n", "\n", "\n", "\n", "thr-4-var-20-out-1->var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-25-out-0\n", - "\n", - "MAPK_2\n", + "\n", + "MAPK_2\n", "\n", "\n", "\n", "var-25-out-0->thr-4-var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-25-out-0->thr-0-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-24-out-0\n", - "\n", - "3\n", + "\n", + "4\n", "\n", "\n", "\n", "var-25-out-0->thr-1-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-24-out-0\n", - "\n", - "4\n", + "\n", + "3\n", "\n", "\n", "\n", "var-25-out-0->thr-2-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-25-out-0->thr-1-var-39-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-43-out-0\n", - "\n", - "FOXO3_Ub\n", + "\n", + "FOXO3_Ub\n", "\n", "\n", "\n", "var-25-out-0->var-43-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-25-out-0->thr-2-var-46-out-1\n", - "\n", - "\n", + "var-25-out-0->thr-3-var-46-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-25-out-0->thr-1-var-47-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-5-var-20-out-1->var-20-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-21-out-0\n", - "\n", - "RAS\n", + "\n", + "RAS\n", "\n", "\n", "\n", "thr-0-var-22-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", "\n", "var-21-out-0->thr-0-var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-21-out-0->fus-0-thr-0-var-23-out-0\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-21-out-0->thr-2-var-24-out-0\n", - "\n", - "\n", + "var-21-out-0->thr-1-var-24-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-21-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-21-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-21-out-1\n", - "\n", - "RAS\n", + "\n", + "RAS\n", "\n", - "\n", + "\n", "\n", - "thr-2-var-22-out-1\n", - "\n", - "2\n", + "thr-3-var-22-out-1\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-21-out-1->thr-2-var-22-out-1\n", - "\n", - "\n", + "var-21-out-1->thr-3-var-22-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-21-out-1->thr-1-var-23-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-3-var-24-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-21-out-1->fus-0-thr-3-var-24-out-1\n", - "\n", + "var-21-out-1->fus-0-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", - "\n", - "fus-1-thr-3-var-24-out-1\n", - "\n", + "\n", + "\n", + "fus-1-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-21-out-1->fus-1-thr-3-var-24-out-1\n", - "\n", + "var-21-out-1->fus-1-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-21-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", + "var-21-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", "\n", "thr-0-var-21-out-0->var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-22-out-0\n", - "\n", - "RAS_2\n", + "\n", + "RAS_2\n", "\n", "\n", "\n", "var-22-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-22-out-0->fus-0-thr-0-var-23-out-0\n", - "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-22-out-0->thr-2-var-24-out-0\n", - "\n", - "\n", + "var-22-out-0->thr-1-var-24-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-25-out-0\n", - "\n", + "\n", + "\n", + "thr-0-var-25-out-0\n", + "\n", + "2\n", "\n", - "\n", + "\n", "\n", - "var-22-out-0->fus-0-thr-0-var-25-out-0\n", - "\n", + "var-22-out-0->thr-0-var-25-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-1-thr-0-var-25-out-0\n", - "\n", - "\n", - "\n", + "\n", "\n", - "var-22-out-0->fus-1-thr-0-var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-22-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-22-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "var-23-out-0\n", - "\n", - "RAS_3\n", + "\n", + "RAS_3\n", "\n", "\n", - "\n", + "\n", "var-23-out-0->thr-0-var-21-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-23-out-0->thr-0-var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-23-out-0->thr-1-var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-23-out-0->thr-0-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", + "\n", + "var-23-out-0->thr-1-var-24-out-0\n", + "\n", + "\n", + "\n", + "\n", "\n", - "var-23-out-0->thr-2-var-24-out-0\n", - "\n", - "\n", + "var-23-out-0->thr-0-var-25-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-23-out-0->fus-0-thr-0-var-25-out-0\n", - "\n", + "var-23-out-0->thr-3-var-25-out-0\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "var-23-out-0->fus-1-thr-0-var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-23-out-0->thr-2-var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-23-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "var-23-out-0->thr-0-var-26-out-0\n", + "\n", + "\n", "\n", "\n", "\n", "thr-1-var-21-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-21-out-1->var-21-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-21-out-1->thr-1-var-21-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-22-out-1\n", - "\n", - "RAS_2\n", + "\n", + "RAS_2\n", "\n", "\n", - "\n", + "\n", "var-22-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-22-out-1->thr-1-var-23-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-22-out-1->fus-0-thr-3-var-24-out-1\n", - "\n", + "\n", + "\n", + "var-22-out-1->fus-0-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-22-out-1->fus-1-thr-3-var-24-out-1\n", - "\n", + "\n", + "\n", + "var-22-out-1->fus-1-thr-4-var-24-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-22-out-1->thr-4-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-22-out-1->thr-5-var-25-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-22-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", + "\n", + "\n", + "var-22-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", "\n", "var-23-out-1\n", - "\n", - "RAS_3\n", + "\n", + "RAS_3\n", "\n", "\n", - "\n", + "\n", "var-23-out-1->fus-0-thr-1-var-21-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-23-out-1->var-22-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-4-var-24-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-24-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-23-out-1->thr-4-var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-23-out-1->thr-3-var-24-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-25-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-4-var-25-out-1\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-23-out-1->thr-3-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-23-out-1->thr-4-var-25-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-23-out-1->fus-0-thr-2-var-26-out-1\n", - "\n", + "\n", + "\n", + "var-23-out-1->fus-0-thr-3-var-26-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-22-out-0->var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-22-out-0->var-22-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-22-out-1->var-22-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-22-out-1->var-22-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-22-out-1->thr-2-var-22-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-22-out-1->thr-3-var-22-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-23-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-23-out-0->var-23-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-23-out-0->thr-0-var-23-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-23-out-1->var-23-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-24-out-0\n", - "\n", - "MAPK\n", + "\n", + "MAPK\n", "\n", "\n", - "\n", + "\n", "var-24-out-0->var-25-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-24-out-0->thr-1-var-47-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-24-out-1->thr-3-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-24-out-1->thr-4-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "var-24-out-1->thr-5-var-25-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-24-out-1->fus-0-thr-0-var-47-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-24-out-0->var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-24-out-0->var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-2-var-24-out-0->var-24-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-29-out-0\n", - "\n", - "PIP3\n", + "\n", + "PIP3\n", "\n", - "\n", - "\n", - "var-29-out-0->thr-1-var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-29-out-0->thr-2-var-24-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-29-out-0->fus-0-thr-0-var-25-out-0\n", - "\n", + "\n", + "\n", + "thr-1-var-25-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-29-out-0->fus-1-thr-0-var-25-out-0\n", - "\n", + "\n", + "\n", + "var-29-out-0->thr-1-var-25-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-30-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-29-out-0->fus-0-thr-0-var-30-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-31-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-29-out-0->thr-0-var-31-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-32-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-29-out-0->thr-0-var-32-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-29-out-0->fus-0-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-1-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "thr-1-var-33-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-29-out-0->fus-1-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "var-29-out-0->thr-1-var-33-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-0\n", - "\n", - "PIP3_2\n", - "\n", - "\n", - "\n", - "var-30-out-0->thr-1-var-24-out-0\n", - "\n", - "\n", + "\n", + "PIP3_2\n", "\n", - "\n", - "\n", - "var-30-out-0->fus-0-thr-0-var-25-out-0\n", - "\n", + "\n", + "\n", + "var-30-out-0->thr-2-var-24-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-30-out-0->fus-1-thr-0-var-25-out-0\n", - "\n", + "\n", + "\n", + "var-30-out-0->thr-1-var-25-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-29-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-30-out-0->thr-0-var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-29-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-30-out-0->thr-1-var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-0->thr-0-var-31-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-0->thr-0-var-32-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-30-out-0->fus-0-thr-0-var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-30-out-0->fus-1-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "var-30-out-0->thr-0-var-33-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-0->thr-1-var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-24-out-0->var-24-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-24-out-1->var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-24-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-3-var-24-out-1->thr-3-var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "var-29-out-1\n", - "\n", - "PIP3\n", + "\n", + "PIP3\n", "\n", "\n", - "\n", + "\n", "var-29-out-1->fus-0-thr-3-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-29-out-1->fus-1-thr-3-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-4-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-29-out-1->fus-0-thr-4-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-3-var-25-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-29-out-1->fus-0-thr-3-var-25-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-4-var-25-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-29-out-1->fus-0-thr-4-var-25-out-1\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-5-var-25-out-1\n", + "\n", + "\n", + "\n", + "\n", + "var-29-out-1->fus-0-thr-5-var-25-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-30-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-29-out-1->thr-2-var-30-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-31-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-29-out-1->fus-0-thr-1-var-31-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-32-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-29-out-1->fus-0-thr-2-var-32-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-29-out-1->thr-3-var-33-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-29-out-1->thr-4-var-33-out-1\n", + "\n", + "\n", "\n", "\n", "\n", "var-30-out-1\n", - "\n", - "PIP3_2\n", + "\n", + "PIP3_2\n", "\n", "\n", - "\n", + "\n", "var-30-out-1->fus-0-thr-3-var-24-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-1->var-29-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-30-out-1->fus-1-thr-3-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-30-out-1->fus-0-thr-4-var-24-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-30-out-1->fus-0-thr-3-var-25-out-1\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-1->fus-0-thr-4-var-25-out-1\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "var-30-out-1->fus-0-thr-5-var-25-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-1->fus-0-thr-1-var-31-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-30-out-1->fus-0-thr-2-var-32-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-33-out-1\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "var-30-out-1->thr-2-var-33-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-33-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "fus-1-thr-3-var-24-out-1->thr-3-var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-30-out-1->thr-3-var-33-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-24-out-1->var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-4-var-24-out-1->thr-4-var-24-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-25-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "fus-1-thr-4-var-24-out-1->thr-4-var-24-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-25-out-0->var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-25-out-0->thr-0-var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-0-var-25-out-0->thr-0-var-25-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-25-out-0->var-25-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-25-out-1->var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-1-var-25-out-0->var-25-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-3-var-25-out-1->thr-3-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-25-out-0->var-25-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-25-out-1->var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-4-var-25-out-1->thr-4-var-25-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-5-var-25-out-1->var-25-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-5-var-25-out-1->thr-5-var-25-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-26-out-0\n", - "\n", - "PI3K\n", + "\n", + "PI3K\n", "\n", "\n", - "\n", + "\n", "var-26-out-0->fus-0-thr-0-var-27-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-26-out-0->thr-0-var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-26-out-1\n", - "\n", - "PI3K\n", + "\n", + "PI3K\n", "\n", "\n", - "\n", + "\n", "var-26-out-1->thr-2-var-27-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-29-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-29-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-26-out-1->fus-0-thr-2-var-29-out-1\n", - "\n", + "\n", + "\n", + "var-26-out-1->fus-0-thr-3-var-29-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-26-out-0->var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-0->thr-0-var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-0->thr-1-var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-0->thr-0-var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-0->fus-0-thr-0-var-30-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-26-out-0->var-26-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-2-var-26-out-1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-2-var-26-out-1->var-26-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-26-out-1->thr-2-var-26-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-3-var-26-out-1\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "thr-3-var-26-out-1->var-26-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-3-var-26-out-1->thr-3-var-26-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-1\n", - "\n", - "PI3K_2\n", + "\n", + "PI3K_2\n", "\n", - "\n", - "\n", - "var-27-out-1->fus-0-thr-3-var-26-out-1\n", - "\n", + "\n", + "\n", + "var-27-out-1->fus-0-thr-2-var-26-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-27-out-1->fus-0-thr-2-var-29-out-1\n", - "\n", + "\n", + "\n", + "var-27-out-1->fus-0-thr-3-var-29-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-27-out-1->thr-2-var-30-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-26-out-1->var-26-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-26-out-1->thr-3-var-26-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-27-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-27-out-0->var-27-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-27-out-0->thr-0-var-27-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-27-out-1->var-27-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-28-out-0\n", - "\n", - "PTEN\n", + "\n", + "PTEN\n", "\n", "\n", - "\n", + "\n", "var-28-out-0->var-28-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-29-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-29-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-28-out-0->thr-2-var-29-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-28-out-0->thr-3-var-29-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-28-out-0->thr-2-var-30-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-28-out-1\n", - "\n", - "PTEN\n", + "\n", + "PTEN\n", "\n", "\n", - "\n", + "\n", "var-28-out-1->var-30-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-28-out-1->var-28-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-28-out-1->thr-1-var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-29-out-0->var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-29-out-0->var-29-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-29-out-1->var-29-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-29-out-1->var-29-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-29-out-1->thr-2-var-29-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-29-out-1->thr-3-var-29-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-30-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-30-out-0->var-30-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-30-out-0->thr-0-var-30-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-30-out-1->var-30-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-31-out-0\n", - "\n", - "PDK1_pm\n", + "\n", + "PDK1_pm\n", "\n", - "\n", - "\n", - "var-31-out-0->fus-0-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "thr-2-var-33-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-31-out-0->fus-1-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "var-31-out-0->thr-2-var-33-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-31-out-1\n", - "\n", - "PDK1_pm\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-33-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-31-out-1->fus-0-thr-2-var-33-out-1\n", - "\n", + "\n", + "PDK1_pm\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-3-var-33-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-31-out-1->fus-0-thr-3-var-33-out-1\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-4-var-33-out-1\n", + "\n", + "\n", + "\n", + "\n", + "var-31-out-1->fus-0-thr-4-var-33-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-31-out-0->var-31-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-31-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-31-out-1->var-31-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-31-out-1->thr-1-var-31-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-32-out-0->fus-0-thr-0-var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-32-out-0->fus-1-thr-0-var-33-out-0\n", - "\n", + "\n", + "\n", + "var-32-out-0->thr-2-var-33-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-32-out-1\n", - "\n", - "mTORC2_pm\n", - "\n", - "\n", - "\n", - "var-32-out-1->fus-0-thr-2-var-33-out-1\n", - "\n", + "\n", + "mTORC2_pm\n", "\n", "\n", - "\n", + "\n", "var-32-out-1->fus-0-thr-3-var-33-out-1\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "var-32-out-1->fus-0-thr-4-var-33-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-32-out-0->var-32-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-32-out-1->var-32-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-32-out-1->thr-2-var-32-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-0\n", - "\n", - "AKT\n", + "\n", + "AKT\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->thr-2-var-35-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-38-out-1\n", - "\n", - "KMT2D\n", + "\n", + "KMT2D\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->var-38-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->thr-1-var-39-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->thr-1-var-40-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->thr-1-var-42-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-0->thr-1-var-47-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-1\n", - "\n", - "AKT\n", + "\n", + "AKT\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->fus-0-thr-0-var-35-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-38-out-0\n", - "\n", - "KMT2D\n", + "\n", + "KMT2D\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->var-38-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->fus-0-thr-0-var-39-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->fus-0-thr-0-var-40-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->fus-0-thr-0-var-42-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-33-out-1->fus-0-thr-0-var-47-out-1\n", - "\n", - "\n", - "\n", - "\n", - "thr-0-var-33-out-0\n", - "\n", - "2\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-33-out-0->var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-33-out-0->thr-0-var-33-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-0-var-33-out-0->thr-0-var-33-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-33-out-0->var-33-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-33-out-1->var-33-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-33-out-1->thr-2-var-33-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-2-var-33-out-0->var-33-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-33-out-1->var-33-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-3-var-33-out-1->thr-3-var-33-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-4-var-33-out-1->var-33-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-4-var-33-out-1->thr-4-var-33-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-34-out-0\n", - "\n", - "p21_p27_T\n", + "\n", + "p21_p27_T\n", "\n", "\n", - "\n", + "\n", "thr-0-var-35-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-34-out-0->thr-0-var-35-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-35-out-1\n", - "\n", - "p21_p27\n", + "\n", + "p21_p27\n", "\n", "\n", - "\n", + "\n", "var-34-out-1->var-35-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-34-out-0->var-34-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-34-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-34-out-1->thr-0-var-34-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-59-out-1\n", - "\n", - "MYC\n", + "\n", + "MYC\n", "\n", "\n", - "\n", + "\n", "var-59-out-1->fus-0-thr-0-var-34-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-60-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-59-out-1->thr-1-var-60-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-61-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-59-out-1->fus-0-thr-1-var-61-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-60-out-1\n", - "\n", - "MYC_2\n", + "\n", + "MYC_2\n", "\n", "\n", - "\n", + "\n", "var-60-out-1->fus-0-thr-0-var-34-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-59-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-60-out-1->fus-0-thr-1-var-59-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-62-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-60-out-1->thr-1-var-62-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-34-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-2-var-34-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "thr-1-var-34-out-1->var-34-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-2-var-34-out-1->var-34-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-59-out-0\n", - "\n", - "MYC\n", + "\n", + "MYC\n", "\n", - "\n", - "\n", - "var-59-out-0->thr-1-var-34-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-59-out-0->thr-2-var-34-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-60-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-59-out-0->fus-0-thr-0-var-60-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-61-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-59-out-0->thr-0-var-61-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-60-out-0\n", - "\n", - "MYC_2\n", + "\n", + "MYC_2\n", "\n", - "\n", - "\n", - "var-60-out-0->thr-1-var-34-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-60-out-0->thr-2-var-34-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-59-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-60-out-0->thr-0-var-59-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-62-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-60-out-0->fus-0-thr-0-var-62-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-35-out-0\n", - "\n", - "p21_p27\n", + "\n", + "p21_p27\n", "\n", "\n", - "\n", + "\n", "thr-2-var-37-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-35-out-0->thr-2-var-37-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-37-out-0\n", - "\n", - "cycE_CDK2\n", + "\n", + "cycE_CDK2\n", "\n", "\n", - "\n", + "\n", "var-35-out-1->var-37-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-35-out-0->var-35-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-35-out-1->thr-0-var-35-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-35-out-1->var-35-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-36-out-0\n", - "\n", - "cycE_CDK2_T\n", + "\n", + "cycE_CDK2_T\n", "\n", "\n", - "\n", + "\n", "var-36-out-0->var-37-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-36-out-1\n", - "\n", - "cycE_CDK2_T\n", + "\n", + "cycE_CDK2_T\n", "\n", "\n", - "\n", + "\n", "var-36-out-1->thr-2-var-37-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-36-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "thr-0-var-36-out-0->var-36-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-70-out-0\n", - "\n", - "E2F\n", + "\n", + "E2F\n", "\n", "\n", - "\n", + "\n", "var-70-out-0->thr-0-var-36-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-71-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-70-out-0->fus-0-thr-0-var-71-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-70-out-0->fus-0-thr-1-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-73-out-0\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-70-out-0->thr-0-var-73-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-0\n", - "\n", - "E2F_2\n", + "\n", + "E2F_2\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->thr-0-var-36-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-70-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->thr-0-var-70-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->fus-0-thr-1-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->thr-0-var-73-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-74-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->thr-0-var-74-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-75-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-0->fus-0-thr-0-var-75-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0\n", - "\n", - "E2F_3\n", + "\n", + "E2F_3\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-36-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-70-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-71-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-71-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->fus-0-thr-0-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-73-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-74-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-75-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->thr-0-var-75-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-76-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-0->fus-0-thr-0-var-76-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-36-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-36-out-1->var-36-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-36-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-36-out-1->thr-1-var-36-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-70-out-1\n", - "\n", - "E2F\n", + "\n", + "E2F\n", "\n", "\n", - "\n", + "\n", "var-70-out-1->fus-0-thr-1-var-36-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-71-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-70-out-1->thr-2-var-71-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-72-out-1\n", - "\n", - "3\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-70-out-1->thr-2-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-72-out-1\n", - "\n", - "4\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-70-out-1->thr-3-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-73-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-70-out-1->fus-0-thr-1-var-73-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1\n", - "\n", - "E2F_2\n", + "\n", + "E2F_2\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->fus-0-thr-1-var-36-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-70-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->fus-0-thr-1-var-70-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->thr-2-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->thr-3-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->fus-0-thr-1-var-73-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-74-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->fus-0-thr-1-var-74-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-75-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-71-out-1->thr-2-var-75-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-1\n", - "\n", - "E2F_3\n", + "\n", + "E2F_3\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->fus-0-thr-1-var-36-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->var-71-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->fus-0-thr-1-var-70-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-72-out-1->thr-3-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-72-out-1->thr-2-var-72-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->fus-0-thr-1-var-73-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->fus-0-thr-1-var-74-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-75-out-1\n", - "\n", - "Proliferation_3\n", + "\n", + "Proliferation_3\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->var-75-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-76-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-72-out-1->thr-1-var-76-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-67-out-0\n", - "\n", - "5\n", + "\n", + "5\n", "\n", "\n", - "\n", + "\n", "var-37-out-0->thr-0-var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-68-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-68-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-37-out-0->fus-0-thr-0-var-68-out-0\n", - "\n", + "\n", + "\n", + "var-37-out-0->fus-0-thr-1-var-68-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-69-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-37-out-0->fus-0-thr-0-var-69-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-37-out-1\n", - "\n", - "cycE_CDK2\n", + "\n", + "cycE_CDK2\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-37-out-1->fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "thr-4-var-68-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-3-var-68-out-1\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-37-out-1->thr-4-var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-37-out-1->thr-3-var-68-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-69-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-37-out-1->thr-1-var-69-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-37-out-1->var-37-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-38-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-58-out-1\n", - "\n", - "6\n", + "\n", + "6\n", "\n", "\n", - "\n", + "\n", "var-38-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-39-out-0\n", - "\n", - "TSC\n", + "\n", + "TSC\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-41-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-39-out-0->fus-0-thr-2-var-41-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-39-out-1\n", - "\n", - "TSC\n", + "\n", + "TSC\n", "\n", "\n", - "\n", + "\n", "thr-1-var-41-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-39-out-1->thr-1-var-41-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-39-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-39-out-0->var-39-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-39-out-1->thr-0-var-39-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-39-out-1->var-39-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-40-out-0\n", - "\n", - "PRAS40\n", + "\n", + "PRAS40\n", "\n", "\n", - "\n", + "\n", "var-40-out-0->fus-0-thr-2-var-41-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-40-out-1\n", - "\n", - "PRAS40\n", + "\n", + "PRAS40\n", "\n", "\n", - "\n", + "\n", "var-40-out-1->thr-1-var-41-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-40-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-40-out-0->var-40-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-40-out-1->thr-0-var-40-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-40-out-1->var-40-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-41-out-0->var-50-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-49-out-0\n", - "\n", - "EIF4F\n", + "\n", + "EIF4F\n", "\n", "\n", - "\n", + "\n", "var-41-out-0->var-49-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-41-out-1\n", - "\n", - "mTORC1\n", + "\n", + "mTORC1\n", "\n", "\n", - "\n", + "\n", "var-41-out-1->var-50-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-49-out-1\n", - "\n", - "EIF4F\n", + "\n", + "EIF4F\n", "\n", "\n", - "\n", + "\n", "var-41-out-1->var-49-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-41-out-0->var-41-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-41-out-1->var-41-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-41-out-0->thr-2-var-41-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-42-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-42-out-0->var-42-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-42-out-1->thr-0-var-42-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-43-out-1->fus-0-thr-0-var-42-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-42-out-1->var-42-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-43-out-0->thr-1-var-42-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-44-out-0\n", - "\n", - "BIM_T\n", + "\n", + "BIM_T\n", "\n", "\n", - "\n", + "\n", "var-44-out-0->var-44-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-44-out-0->thr-0-var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-44-out-0->thr-1-var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-44-out-1\n", - "\n", - "BIM_T\n", + "\n", + "BIM_T\n", "\n", "\n", - "\n", + "\n", "var-44-out-1->var-44-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-46-out-1\n", - "\n", - "BIM\n", + "\n", + "BIM\n", "\n", "\n", - "\n", + "\n", "var-44-out-1->var-46-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-45-out-0\n", - "\n", - "BCL2_T\n", + "\n", + "BCL2_T\n", "\n", "\n", - "\n", + "\n", "var-45-out-0->var-45-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-63-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-45-out-0->thr-0-var-63-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-45-out-1\n", - "\n", - "BCL2_T\n", + "\n", + "BCL2_T\n", "\n", "\n", - "\n", + "\n", "var-45-out-1->var-45-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-63-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-45-out-1->fus-0-thr-1-var-63-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-46-out-0\n", - "\n", - "BIM\n", + "\n", + "BIM\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-77-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-46-out-0->fus-0-thr-0-var-77-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-77-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-46-out-0->thr-1-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-77-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-4-var-77-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-46-out-0->fus-0-thr-2-var-77-out-0\n", - "\n", + "\n", + "\n", + "var-46-out-0->fus-0-thr-4-var-77-out-0\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-78-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-78-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-46-out-0->fus-0-thr-0-var-78-out-0\n", - "\n", + "\n", + "\n", + "var-46-out-0->fus-0-thr-1-var-78-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-79-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-46-out-0->fus-0-thr-0-var-79-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-77-out-1\n", - "\n", + "\n", + "\n", + "thr-3-var-77-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-46-out-1->fus-0-thr-2-var-77-out-1\n", - "\n", + "\n", + "\n", + "var-46-out-1->thr-3-var-77-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-4-var-77-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "fus-0-thr-4-var-77-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-46-out-1->thr-4-var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-46-out-1->fus-0-thr-4-var-77-out-1\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-78-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-3-var-78-out-1\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-46-out-1->thr-2-var-78-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-46-out-1->thr-3-var-78-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-79-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-46-out-1->thr-3-var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-46-out-0->var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-46-out-0->var-46-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-46-out-1->var-46-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-46-out-1->var-46-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-47-out-0\n", - "\n", - "BAD\n", + "\n", + "BAD\n", "\n", "\n", - "\n", + "\n", "var-47-out-0->fus-0-thr-0-var-77-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-47-out-0->thr-1-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-47-out-0->fus-0-thr-2-var-77-out-0\n", - "\n", + "\n", + "\n", + "var-47-out-0->fus-0-thr-4-var-77-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-47-out-0->fus-0-thr-0-var-78-out-0\n", - "\n", + "\n", + "\n", + "var-47-out-0->fus-0-thr-1-var-78-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-47-out-0->fus-0-thr-0-var-79-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-47-out-1\n", - "\n", - "BAD\n", + "\n", + "BAD\n", "\n", - "\n", - "\n", - "var-47-out-1->fus-0-thr-2-var-77-out-1\n", - "\n", + "\n", + "\n", + "var-47-out-1->thr-3-var-77-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-47-out-1->thr-4-var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-47-out-1->fus-0-thr-4-var-77-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-47-out-1->thr-2-var-78-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-47-out-1->thr-3-var-78-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-47-out-1->thr-3-var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-47-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-47-out-0->var-47-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-47-out-1->thr-0-var-47-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-47-out-1->var-47-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-48-out-0\n", - "\n", - "MCL1\n", + "\n", + "MCL1\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-78-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-78-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-48-out-0->fus-0-thr-2-var-78-out-0\n", - "\n", + "\n", + "\n", + "var-48-out-0->fus-0-thr-3-var-78-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-48-out-0->thr-3-var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-48-out-1\n", - "\n", - "MCL1\n", + "\n", + "MCL1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-77-out-0\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-48-out-1->thr-0-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-78-out-0\n", - "\n", - "3\n", + "\n", + "\n", + "thr-0-var-78-out-0\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-48-out-1->thr-1-var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-48-out-1->thr-0-var-78-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-79-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-48-out-1->fus-0-thr-1-var-79-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-0\n", - "\n", - "Translation\n", + "\n", + "Translation\n", "\n", "\n", - "\n", + "\n", "var-51-out-0->var-48-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-0->thr-0-var-73-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-0->thr-0-var-74-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-0->fus-0-thr-0-var-75-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-0->fus-0-thr-0-var-76-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-1\n", - "\n", - "Translation\n", + "\n", + "Translation\n", "\n", "\n", - "\n", + "\n", "var-51-out-1->var-48-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-1->fus-0-thr-1-var-73-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-1->fus-0-thr-1-var-74-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-1->thr-2-var-75-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-51-out-1->thr-1-var-76-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-49-out-0->fus-0-thr-0-var-51-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-49-out-1->thr-1-var-51-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-51-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-51-out-0->var-51-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-51-out-0->thr-0-var-51-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-51-out-1->var-51-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-0\n", - "\n", - "ER\n", + "\n", + "ER\n", "\n", "\n", - "\n", + "\n", "var-52-out-0->var-52-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-52-out-0->thr-1-var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-52-out-0->thr-0-var-53-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-52-out-0->fus-0-thr-0-var-54-out-0\n", - "\n", + "\n", + "\n", + "var-52-out-0->fus-0-thr-1-var-54-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-57-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-52-out-0->thr-0-var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-1\n", - "\n", - "ER\n", + "\n", + "ER\n", "\n", "\n", - "\n", + "\n", "var-52-out-1->var-52-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-1->fus-0-thr-2-var-53-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-1->thr-2-var-54-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-57-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-57-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-52-out-1->thr-2-var-57-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-52-out-1->thr-3-var-57-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-52-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-53-out-0\n", - "\n", - "ESR1\n", + "\n", + "ESR1\n", "\n", - "\n", - "\n", - "var-53-out-0->fus-0-thr-0-var-54-out-0\n", - "\n", + "\n", + "\n", + "var-53-out-0->fus-0-thr-1-var-54-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-57-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-53-out-0->thr-1-var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-53-out-1\n", - "\n", - "ESR1\n", + "\n", + "ESR1\n", "\n", "\n", - "\n", + "\n", "var-53-out-1->thr-2-var-54-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-57-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-57-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-53-out-1->fus-0-thr-2-var-57-out-1\n", - "\n", + "\n", + "\n", + "var-53-out-1->fus-0-thr-3-var-57-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-53-out-0->var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-0->thr-0-var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-0->thr-1-var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-0->thr-1-var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-53-out-0->var-53-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-53-out-1->var-53-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-53-out-1->thr-2-var-53-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-1\n", - "\n", - "ESR1_2\n", + "\n", + "ESR1_2\n", "\n", "\n", - "\n", + "\n", "var-54-out-1->var-53-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-54-out-1->fus-0-thr-2-var-57-out-1\n", - "\n", + "\n", + "\n", + "var-54-out-1->fus-0-thr-3-var-57-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-54-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-54-out-0\n", - "\n", - "1\n", + "\n", + "\n", + "thr-1-var-54-out-0\n", + "\n", + "1\n", "\n", - "\n", - "\n", - "thr-0-var-54-out-0->var-54-out-0\n", - "\n", - "\n", + "\n", + "\n", + "thr-1-var-54-out-0->var-54-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-54-out-0->thr-0-var-54-out-0\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-54-out-0->thr-1-var-54-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-54-out-1->var-54-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-55-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-55-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-56-out-0\n", - "\n", - "PBX1\n", + "\n", + "PBX1\n", "\n", "\n", - "\n", + "\n", "var-56-out-0->var-56-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-56-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-56-out-1\n", - "\n", - "PBX1\n", + "\n", + "PBX1\n", "\n", "\n", - "\n", + "\n", "var-56-out-1->var-56-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-56-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-57-out-0\n", - "\n", - "ER_transcription\n", + "\n", + "ER_transcription\n", "\n", "\n", - "\n", + "\n", "var-57-out-0->fus-0-thr-0-var-58-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-57-out-0->thr-0-var-59-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-57-out-1\n", - "\n", - "ER_transcription\n", + "\n", + "ER_transcription\n", "\n", "\n", - "\n", + "\n", "var-57-out-1->thr-1-var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-57-out-1->fus-0-thr-1-var-59-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-57-out-0->var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-0\n", - "\n", - "ER_transcription_2\n", + "\n", + "ER_transcription_2\n", "\n", "\n", - "\n", + "\n", "var-58-out-0->thr-0-var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-0->thr-1-var-57-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-0->fus-0-thr-0-var-60-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-0->thr-0-var-63-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-57-out-0->var-57-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-57-out-1->var-57-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-57-out-1->thr-2-var-57-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-1\n", - "\n", - "ER_transcription_2\n", + "\n", + "ER_transcription_2\n", "\n", "\n", - "\n", + "\n", "var-58-out-1->var-57-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-1->thr-1-var-60-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-58-out-1->fus-0-thr-1-var-63-out-1\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-57-out-1->var-57-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-57-out-1->thr-3-var-57-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-58-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-58-out-0->var-58-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-58-out-0->thr-0-var-58-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-58-out-1->var-58-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-59-out-0->var-59-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-59-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-59-out-1->var-59-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-59-out-1->thr-1-var-59-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-60-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-60-out-0->var-60-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-60-out-0->thr-0-var-60-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-60-out-1->var-60-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-61-out-0\n", - "\n", - "cyclinD\n", + "\n", + "cyclinD\n", "\n", "\n", - "\n", + "\n", "var-61-out-0->fus-0-thr-0-var-62-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-65-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-61-out-0->thr-1-var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-61-out-1\n", - "\n", - "cyclinD\n", + "\n", + "cyclinD\n", "\n", "\n", - "\n", + "\n", "var-61-out-1->thr-1-var-62-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-65-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-65-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-61-out-1->fus-0-thr-2-var-65-out-1\n", - "\n", + "\n", + "\n", + "var-61-out-1->fus-0-thr-3-var-65-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-61-out-0->var-61-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-62-out-0\n", - "\n", - "cyclinD_2\n", + "\n", + "cyclinD_2\n", "\n", "\n", - "\n", + "\n", "var-62-out-0->thr-0-var-61-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-62-out-0->thr-1-var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-66-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-62-out-0->fus-0-thr-0-var-66-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-61-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-61-out-1->var-61-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-61-out-1->thr-1-var-61-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-62-out-1\n", - "\n", - "cyclinD_2\n", + "\n", + "cyclinD_2\n", "\n", "\n", - "\n", + "\n", "var-62-out-1->fus-0-thr-1-var-61-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-62-out-1->fus-0-thr-2-var-65-out-1\n", - "\n", + "\n", + "\n", + "var-62-out-1->fus-0-thr-3-var-65-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-66-out-1\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-62-out-1->thr-1-var-66-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-62-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-62-out-0->var-62-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-62-out-0->thr-0-var-62-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-62-out-1->var-62-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-63-out-0\n", - "\n", - "BCL2\n", + "\n", + "BCL2\n", "\n", - "\n", - "\n", - "var-63-out-0->fus-0-thr-2-var-78-out-0\n", - "\n", + "\n", + "\n", + "var-63-out-0->fus-0-thr-3-var-78-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-63-out-0->thr-3-var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-63-out-1\n", - "\n", - "BCL2\n", + "\n", + "BCL2\n", "\n", "\n", - "\n", + "\n", "var-63-out-1->thr-0-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-63-out-1->thr-1-var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-63-out-1->thr-0-var-78-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-63-out-1->fus-0-thr-1-var-79-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-63-out-0->var-63-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-63-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-63-out-1->var-63-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-63-out-1->thr-1-var-63-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-65-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-64-out-0->thr-0-var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-64-out-0->fus-0-thr-0-var-66-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-65-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-65-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-64-out-1->thr-2-var-65-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-64-out-1->thr-3-var-65-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-64-out-1->thr-1-var-66-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-65-out-0\n", - "\n", - "cycD_CDK46\n", + "\n", + "cycD_CDK46\n", "\n", "\n", - "\n", + "\n", "var-65-out-0->fus-0-thr-0-var-66-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-65-out-0->thr-0-var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-65-out-0->fus-0-thr-0-var-68-out-0\n", - "\n", + "\n", + "\n", + "var-65-out-0->fus-0-thr-1-var-68-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-65-out-1\n", - "\n", - "cycD_CDK46\n", + "\n", + "cycD_CDK46\n", "\n", "\n", - "\n", + "\n", "var-65-out-1->thr-1-var-66-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-65-out-1->fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-65-out-1->thr-4-var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-65-out-1->thr-3-var-68-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-65-out-0->var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-0\n", - "\n", - "cycD_CDK46_2\n", + "\n", + "cycD_CDK46_2\n", "\n", "\n", - "\n", + "\n", "var-66-out-0->thr-0-var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-0->thr-1-var-65-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-0->thr-0-var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-68-out-0\n", - "\n", - "3\n", + "\n", + "\n", + "thr-1-var-68-out-0\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-66-out-0->thr-0-var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-66-out-0->thr-1-var-68-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-0->fus-0-thr-0-var-69-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-65-out-0->var-65-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-65-out-1->var-65-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-65-out-1->thr-2-var-65-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-1\n", - "\n", - "cycD_CDK46_2\n", + "\n", + "cycD_CDK46_2\n", "\n", "\n", - "\n", + "\n", "var-66-out-1->var-65-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-1->fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-68-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-66-out-1->thr-2-var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-66-out-1->thr-1-var-69-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-65-out-1->var-65-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-65-out-1->thr-3-var-65-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-66-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-66-out-0->var-66-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-66-out-0->thr-0-var-66-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-66-out-1->var-66-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-0\n", - "\n", - "pRb\n", + "\n", + "pRb\n", "\n", - "\n", - "\n", - "thr-1-var-68-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-0-var-68-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-67-out-0->thr-1-var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-67-out-0->thr-0-var-68-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-0->fus-0-thr-0-var-69-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-0->thr-0-var-70-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-1\n", - "\n", - "pRb\n", + "\n", + "pRb\n", "\n", "\n", - "\n", + "\n", "var-67-out-1->thr-2-var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-67-out-1->thr-4-var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-67-out-1->thr-3-var-68-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-1->thr-1-var-69-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-67-out-1->fus-0-thr-1-var-70-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-67-out-0->var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-0\n", - "\n", - "pRb_2\n", + "\n", + "pRb_2\n", "\n", "\n", - "\n", + "\n", "var-68-out-0->thr-0-var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-0->fus-0-thr-0-var-69-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-0->fus-0-thr-0-var-71-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-0->fus-0-thr-0-var-72-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-69-out-0\n", - "\n", - "pRb_3\n", + "\n", + "pRb_3\n", "\n", "\n", - "\n", + "\n", "var-69-out-0->thr-0-var-67-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-69-out-0->thr-0-var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-69-out-0->thr-1-var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-72-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-69-out-0->thr-0-var-72-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-67-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-67-out-1->var-67-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-67-out-1->thr-1-var-67-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-1\n", - "\n", - "pRb_2\n", + "\n", + "pRb_2\n", "\n", "\n", - "\n", + "\n", "var-68-out-1->fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-1->thr-1-var-69-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-68-out-1->thr-2-var-71-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-68-out-1->thr-3-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-68-out-1->thr-2-var-72-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-69-out-1\n", - "\n", - "pRb_3\n", + "\n", + "pRb_3\n", "\n", "\n", - "\n", + "\n", "var-69-out-1->fus-0-thr-1-var-67-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-69-out-1->var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-69-out-1->thr-2-var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-69-out-1->thr-3-var-72-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-68-out-0->var-68-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-68-out-0->thr-0-var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-68-out-0->var-68-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-1-var-68-out-0->thr-1-var-68-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-68-out-1->var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-4-var-68-out-1->var-68-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-68-out-1->var-68-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-69-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-69-out-0->var-69-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-69-out-0->thr-0-var-69-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-69-out-1->var-69-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-70-out-0->var-70-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-70-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-70-out-1->var-70-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-70-out-1->thr-1-var-70-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-71-out-0->var-71-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-71-out-0->thr-0-var-71-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-71-out-1->var-71-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-72-out-0->var-72-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-72-out-0->thr-0-var-72-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-72-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-72-out-0->var-72-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-72-out-0->thr-1-var-72-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-72-out-1->var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-72-out-1->var-72-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-73-out-0\n", - "\n", - "Proliferation\n", + "\n", + "Proliferation\n", "\n", "\n", - "\n", + "\n", "var-73-out-1\n", - "\n", - "Proliferation\n", + "\n", + "Proliferation\n", "\n", "\n", - "\n", + "\n", "thr-0-var-73-out-0->var-73-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-73-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-73-out-1->var-73-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-73-out-1->thr-1-var-73-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-74-out-0\n", - "\n", - "Proliferation_2\n", + "\n", + "Proliferation_2\n", "\n", "\n", - "\n", + "\n", "var-74-out-1\n", - "\n", - "Proliferation_2\n", + "\n", + "Proliferation_2\n", "\n", "\n", - "\n", + "\n", "thr-0-var-74-out-0->var-74-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-74-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-74-out-1->var-74-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-74-out-1->thr-1-var-74-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-75-out-0\n", - "\n", - "Proliferation_3\n", + "\n", + "Proliferation_3\n", "\n", "\n", - "\n", + "\n", "thr-0-var-75-out-0->var-75-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-75-out-0->thr-0-var-75-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-75-out-1->var-75-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-76-out-0\n", - "\n", - "Proliferation_4\n", + "\n", + "Proliferation_4\n", "\n", "\n", - "\n", + "\n", "var-76-out-1\n", - "\n", - "Proliferation_4\n", + "\n", + "Proliferation_4\n", "\n", "\n", - "\n", + "\n", "thr-0-var-76-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-76-out-0->var-76-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-76-out-0->thr-0-var-76-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-76-out-1->var-76-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-77-out-0\n", - "\n", - "Apoptosis\n", + "\n", + "Apoptosis\n", "\n", "\n", - "\n", + "\n", "var-77-out-0->thr-0-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-77-out-0->thr-1-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-77-out-1\n", - "\n", - "Apoptosis\n", + "\n", + "Apoptosis\n", "\n", "\n", - "\n", + "\n", "var-77-out-1->var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-77-out-0->var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-77-out-0->thr-0-var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-77-out-0->var-77-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-77-out-1\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "thr-2-var-77-out-1->var-77-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-77-out-0->thr-2-var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-77-out-1->var-77-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-77-out-1->thr-2-var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-4-var-77-out-1\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "thr-4-var-77-out-1->var-77-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-4-var-77-out-0->thr-4-var-77-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-4-var-77-out-1->thr-4-var-77-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-78-out-0\n", - "\n", - "Apoptosis_2\n", - "\n", - "\n", - "\n", - "thr-0-var-78-out-0\n", - "\n", - "2\n", + "\n", + "Apoptosis_2\n", "\n", "\n", - "\n", + "\n", "var-78-out-0->thr-0-var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-1-var-78-out-0\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-78-out-0->thr-1-var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-78-out-1\n", - "\n", - "Apoptosis_2\n", + "\n", + "Apoptosis_2\n", "\n", "\n", - "\n", + "\n", "var-78-out-1->var-78-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-78-out-0->var-78-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-78-out-0->thr-0-var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-78-out-0->var-78-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-78-out-1->var-78-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-78-out-0->thr-1-var-78-out-0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-78-out-1->var-78-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-78-out-0->thr-2-var-78-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-78-out-0->thr-3-var-78-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-79-out-0\n", - "\n", - "Apoptosis_3\n", + "\n", + "Apoptosis_3\n", "\n", "\n", - "\n", + "\n", "thr-0-var-79-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-79-out-0->thr-0-var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-79-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-79-out-0->thr-1-var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-79-out-1\n", - "\n", - "Apoptosis_3\n", + "\n", + "Apoptosis_3\n", "\n", "\n", - "\n", + "\n", "var-79-out-1->var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-79-out-0->var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-79-out-0->thr-0-var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-79-out-0->var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-79-out-1->thr-1-var-79-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-79-out-1->var-79-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -6767,7 +6696,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/Dynamics Canalization Map.ipynb b/tutorials/Dynamics Canalization Map.ipynb index 34de982..a5b3118 100644 --- a/tutorials/Dynamics Canalization Map.ipynb +++ b/tutorials/Dynamics Canalization Map.ipynb @@ -24,7 +24,6 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "from cana.datasets.bio import THALIANA\n", "from cana.drawing.canalizing_map import draw_canalizing_map_graphviz\n", "from IPython.display import display" @@ -50,12 +49,13 @@ "\n", "\n", - "\n", - "\n", + "\n", "\n", "\n", + "%3\n", "\n", "\n", "\n", @@ -154,7 +154,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -191,1556 +191,1226 @@ "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", "\n", "\n", "var-0-out-0\n", - "\n", - "AP3\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-0-thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-1-thr-0-var-0-out-0\n", - "\n", + "\n", + "AP3\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-0-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-0-out-0->fus-0-thr-1-var-0-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-1-thr-1-var-0-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-0-out-0->fus-1-thr-1-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-1-thr-3-var-0-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", + "\n", + "thr-0-var-13-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-0-out-0->fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-0-out-0->thr-0-var-13-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-13-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-0-out-0->fus-0-thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-1-thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-0-thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-0->fus-1-thr-2-var-13-out-0\n", - "\n", + "\n", "\n", "\n", "\n", "var-0-out-1\n", - "\n", - "AP3\n", + "\n", + "AP3\n", "\n", - "\n", - "\n", - "thr-5-var-0-out-1\n", - "\n", - "4\n", + "\n", + "\n", + "thr-2-var-0-out-1\n", + "\n", + "4\n", "\n", - "\n", - "\n", - "var-0-out-1->thr-5-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-0-out-1->thr-2-var-0-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-13-out-1\n", + "\n", + "\n", + "\n", + "\n", + "var-0-out-1->fus-0-thr-3-var-13-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-13-out-1\n", - "\n", - "4\n", + "\n", + "4\n", "\n", "\n", - "\n", + "\n", "var-0-out-1->thr-4-var-13-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-5-var-13-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-0-out-1->fus-0-thr-5-var-13-out-1\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "thr-0-var-0-out-0\n", - "\n", - "2\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "thr-0-var-0-out-0->var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-0-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-13-out-0\n", - "\n", - "PI\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-0-thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-13-out-0->fus-1-thr-0-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-13-out-0->fus-0-thr-1-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-4-out-0\n", + "\n", + "AP1\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-1-thr-1-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-4-out-0->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "thr-1-var-2-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-4-out-0->thr-1-var-2-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-1-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-9-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-1-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-4-out-0->fus-0-thr-3-var-9-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-0-thr-0-var-13-out-0\n", - "\n", + "\n", + "\n", + "thr-2-var-12-out-1\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-0-thr-1-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-4-out-0->thr-2-var-12-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-13-out-0->fus-1-thr-1-var-13-out-0\n", - "\n", + "\n", + "\n", + "thr-2-var-13-out-0\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-14-out-0\n", - "\n", - "SEP\n", + "\n", + "\n", + "var-4-out-0->thr-2-var-13-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-0-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0\n", + "\n", + "AG\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-1-thr-0-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "thr-2-var-4-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-1-thr-2-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0->thr-2-var-4-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", + "thr-3-var-4-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-1-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0->thr-3-var-4-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-8-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-2-var-8-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0->fus-0-thr-2-var-8-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-9-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-1-var-9-out-0\n", - "\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-0-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-14-out-0->fus-0-thr-2-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-9-out-0->fus-0-thr-1-var-9-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-14-out-0->fus-1-thr-2-var-13-out-0\n", - "\n", + "\n", + "\n", + "fus-0-thr-0-var-13-out-0\n", + "\n", "\n", - "\n", - "\n", - "fus-1-thr-0-var-0-out-0->thr-0-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-9-out-0->fus-0-thr-0-var-13-out-0\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-0-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "var-9-out-0->thr-2-var-13-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-0-out-0->var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-0-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-1-var-0-out-0->thr-1-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-0-var-0-out-0->thr-0-var-0-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-0\n", - "\n", - "UFO\n", + "\n", + "UFO\n", "\n", - "\n", - "\n", - "var-1-out-0->fus-0-thr-1-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-1-out-0->fus-0-thr-0-var-0-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-0->var-1-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-1-thr-1-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-1-thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-1-thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-4-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-1-out-0->fus-0-thr-4-var-0-out-0\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-6-out-0\n", - "\n", - "LFY\n", - "\n", - "\n", - "\n", - "var-6-out-0->var-14-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-1-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-1-thr-1-var-0-out-0\n", - "\n", + "\n", + "LFY\n", "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-1-thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-6-out-0->fus-0-thr-0-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-6-out-0->fus-1-thr-3-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-14-out-0\n", + "\n", + "SEP\n", "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-4-var-0-out-0\n", - "\n", + "\n", + "\n", + "var-6-out-0->var-14-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-1\n", - "\n", - "EMF1\n", + "\n", + "EMF1\n", "\n", "\n", - "\n", + "\n", "var-6-out-0->var-5-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-4-out-0\n", - "\n", - "3\n", + "\n", + "3\n", "\n", "\n", - "\n", + "\n", "var-6-out-0->thr-0-var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-9-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-6-out-0->thr-0-var-9-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-12-out-1\n", - "\n", - "3\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-6-out-0->thr-2-var-12-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-0-var-13-out-0\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "var-6-out-0->thr-0-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-1-thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-0-thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-0->fus-1-thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "thr-3-var-13-out-0\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "var-6-out-0->thr-3-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-1-var-0-out-0->thr-1-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-0-out-0\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "thr-2-var-0-out-0->var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-0-out-0->thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-2-var-0-out-0->thr-2-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-3-var-0-out-0\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "thr-3-var-0-out-0->var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-3-var-0-out-0->thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-3-var-0-out-0->thr-3-var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-4-var-0-out-0\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "thr-4-var-0-out-0->var-0-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "var-4-out-0\n", - "\n", - "AP1\n", - "\n", - "\n", - "\n", - "var-4-out-0->thr-4-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-2-out-1\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "var-4-out-0->thr-1-var-2-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-9-out-0\n", - "\n", - "\n", - "\n", - "\n", - "var-4-out-0->fus-0-thr-2-var-9-out-0\n", - "\n", + "\n", + "\n", + "var-6-out-0->fus-0-thr-0-var-13-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-4-out-0->thr-2-var-12-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-1-var-13-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-4-out-0->thr-3-var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-6-out-0->thr-1-var-13-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0\n", - "\n", - "AG\n", + "\n", + "\n", + "var-6-out-0->thr-2-var-13-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->thr-4-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", + "thr-1-var-0-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "thr-2-var-4-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-1-var-0-out-0->var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->thr-2-var-4-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-0-out-0->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-4-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "var-13-out-0\n", + "\n", + "PI\n", "\n", - "\n", - "\n", - "var-9-out-0->thr-3-var-4-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-13-out-0->fus-0-thr-1-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-0-thr-2-var-8-out-0\n", - "\n", + "\n", + "\n", + "var-13-out-0->fus-1-thr-1-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-0-thr-1-var-9-out-0\n", - "\n", + "\n", + "\n", + "var-13-out-0->fus-0-thr-1-var-13-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-0-thr-1-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-14-out-0->fus-0-thr-1-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-1-thr-1-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-14-out-0->fus-1-thr-1-var-0-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-0-thr-2-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-14-out-0->fus-0-thr-2-var-8-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->fus-1-thr-2-var-13-out-0\n", - "\n", + "\n", + "\n", + "var-14-out-0->fus-0-thr-1-var-9-out-0\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-0->thr-3-var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-14-out-0->fus-0-thr-1-var-13-out-0\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-4-var-0-out-0->thr-4-var-0-out-0\n", - "\n", - "\n", + "\n", + "\n", + "fus-1-thr-1-var-0-out-0->thr-1-var-0-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-5-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-2-var-0-out-1->var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-13-out-1\n", - "\n", - "PI\n", + "\n", + "PI\n", "\n", - "\n", - "\n", - "var-13-out-1->thr-5-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-13-out-1->thr-2-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-13-out-1->thr-4-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-14-out-1\n", - "\n", - "SEP\n", + "\n", + "SEP\n", "\n", - "\n", - "\n", - "var-14-out-1->thr-5-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-14-out-1->thr-2-var-0-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-8-out-0\n", - "\n", - "2\n", + "\n", + "\n", + "thr-0-var-8-out-0\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-14-out-1->thr-1-var-8-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-14-out-1->thr-0-var-8-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-3-var-9-out-1\n", - "\n", - "3\n", + "\n", + "\n", + "thr-2-var-9-out-1\n", + "\n", + "3\n", "\n", - "\n", - "\n", - "var-14-out-1->thr-3-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-14-out-1->thr-2-var-9-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-14-out-1->thr-4-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-5-var-0-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-5-var-0-out-1->thr-5-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-2-var-0-out-1->thr-2-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-4-out-1\n", - "\n", - "AP1\n", + "\n", + "AP1\n", "\n", - "\n", - "\n", - "var-4-out-1->fus-0-thr-5-var-0-out-1\n", - "\n", + "\n", + "\n", + "var-4-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-2-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-4-out-1->fus-0-thr-0-var-2-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-9-out-0\n", - "\n", - "6\n", + "\n", + "6\n", "\n", "\n", - "\n", + "\n", "var-4-out-1->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-0-var-12-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-1-var-12-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-4-out-1->fus-0-thr-0-var-12-out-1\n", - "\n", + "\n", + "\n", + "var-4-out-1->fus-0-thr-1-var-12-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-4-var-13-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-4-out-1->fus-0-thr-4-var-13-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-9-out-1\n", - "\n", - "AG\n", + "\n", + "AG\n", "\n", "\n", - "\n", + "\n", "var-9-out-1->var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-1->fus-0-thr-5-var-0-out-1\n", - "\n", + "\n", + "\n", + "var-9-out-1->fus-0-thr-2-var-0-out-1\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-1->thr-1-var-8-out-0\n", - "\n", - "\n", + "\n", + "\n", + "var-9-out-1->thr-0-var-8-out-0\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-9-out-1->thr-3-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-9-out-1->thr-2-var-9-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "var-9-out-1->fus-0-thr-3-var-13-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-9-out-1->fus-0-thr-4-var-13-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-9-out-1->fus-0-thr-5-var-13-out-1\n", - "\n", + "\n", "\n", - "\n", - "\n", - "thr-6-var-0-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-0-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "thr-6-var-0-out-1->var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "thr-3-var-0-out-1->var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-1\n", - "\n", - "UFO\n", + "\n", + "UFO\n", "\n", - "\n", - "\n", - "var-1-out-1->thr-6-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-1-out-1->thr-3-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-1-out-1->var-1-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-6-out-1\n", - "\n", - "LFY\n", + "\n", + "LFY\n", "\n", "\n", - "\n", + "\n", "var-6-out-1->var-14-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-6-out-1->thr-6-var-0-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-6-out-1->thr-3-var-0-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-0\n", - "\n", - "EMF1\n", + "\n", + "EMF1\n", "\n", "\n", - "\n", + "\n", "var-6-out-1->var-5-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-4-out-1\n", - "\n", - "\n", - "\n", - "\n", - "var-6-out-1->fus-0-thr-2-var-4-out-1\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-4-out-1\n", + "\n", "\n", - "\n", - "\n", - "thr-2-var-9-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "var-6-out-1->fus-0-thr-3-var-4-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-6-out-1->thr-2-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-9-out-1\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-6-out-1->thr-3-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-5-var-9-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-6-out-1->thr-5-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-6-out-1->fus-0-thr-0-var-12-out-1\n", - "\n", + "\n", + "\n", + "var-6-out-1->fus-0-thr-1-var-12-out-1\n", + "\n", "\n", - "\n", - "\n", - "thr-5-var-13-out-1\n", - "\n", - "2\n", + "\n", + "\n", + "thr-3-var-13-out-1\n", + "\n", + "2\n", "\n", - "\n", - "\n", - "var-6-out-1->thr-5-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-6-out-1->thr-3-var-13-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-2-out-0\n", - "\n", - "FUL\n", + "\n", + "FUL\n", "\n", "\n", - "\n", + "\n", "var-2-out-1\n", - "\n", - "FUL\n", + "\n", + "FUL\n", "\n", "\n", - "\n", + "\n", "thr-0-var-2-out-0\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-0-var-2-out-0->var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-2-out-1->thr-0-var-2-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-12-out-1\n", - "\n", - "TFL1\n", + "\n", + "TFL1\n", "\n", "\n", - "\n", + "\n", "var-12-out-1->fus-0-thr-0-var-2-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-12-out-1->thr-0-var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-6-out-0\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-12-out-1->thr-0-var-6-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-7-out-0\n", - "\n", - "AP2\n", + "\n", + "AP2\n", "\n", "\n", - "\n", + "\n", "var-12-out-1->var-7-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-9-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-12-out-1->fus-0-thr-0-var-9-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-2-out-1->var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-12-out-0\n", - "\n", - "TFL1\n", + "\n", + "TFL1\n", "\n", "\n", - "\n", + "\n", "var-12-out-0->thr-1-var-2-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-12-out-0->thr-3-var-4-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-12-out-0->thr-2-var-4-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-6-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-12-out-0->fus-0-thr-1-var-6-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-7-out-1\n", - "\n", - "AP2\n", + "\n", + "AP2\n", "\n", "\n", - "\n", + "\n", "var-12-out-0->var-7-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-9-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-12-out-0->thr-4-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-3-out-0\n", - "\n", - "FT\n", + "\n", + "FT\n", "\n", "\n", - "\n", + "\n", "var-3-out-0->thr-0-var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-3-out-1\n", - "\n", - "FT\n", + "\n", + "FT\n", "\n", - "\n", - "\n", - "var-3-out-1->fus-0-thr-2-var-4-out-1\n", - "\n", + "\n", + "\n", + "var-3-out-1->fus-0-thr-3-var-4-out-1\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-1->var-3-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-1->thr-0-var-6-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-1->thr-2-var-12-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-0->var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-0->var-3-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-5-out-0->fus-0-thr-1-var-6-out-0\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-4-out-0->var-4-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-4-out-1->var-4-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-4-out-1->thr-2-var-4-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-3-var-4-out-1->var-4-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-4-out-1->thr-3-var-4-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-6-out-0->var-6-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-6-out-1\n", - "\n", - "1\n", + "\n", + "1\n", "\n", "\n", - "\n", + "\n", "thr-1-var-6-out-1->var-6-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-6-out-0->thr-1-var-6-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "var-7-out-0->fus-0-thr-2-var-9-out-0\n", - "\n", + "\n", + "\n", + "var-7-out-0->fus-0-thr-3-var-9-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-7-out-0->thr-4-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-7-out-1->fus-0-thr-0-var-9-out-1\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-7-out-1->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-8-out-0\n", - "\n", - "WUS\n", + "\n", + "WUS\n", "\n", "\n", - "\n", + "\n", "var-8-out-0->var-8-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-8-out-0->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-8-out-1\n", - "\n", - "WUS\n", + "\n", + "WUS\n", "\n", "\n", - "\n", + "\n", "thr-2-var-8-out-1\n", - "\n", - "2\n", + "\n", + "2\n", "\n", "\n", - "\n", + "\n", "var-8-out-1->thr-2-var-8-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-8-out-1->thr-5-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-1-var-8-out-0->var-8-out-0\n", - "\n", - "\n", + "\n", + "\n", + "thr-0-var-8-out-0->var-8-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-8-out-1->var-8-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-2-var-8-out-0->thr-2-var-8-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-9-out-0->var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-9-out-1->thr-0-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-9-out-0->var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-10-out-1\n", - "\n", - "LUG\n", + "\n", + "LUG\n", "\n", "\n", - "\n", + "\n", "var-10-out-1->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-11-out-1\n", - "\n", - "CLF\n", + "\n", + "CLF\n", "\n", "\n", - "\n", + "\n", "var-11-out-1->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-9-out-0->thr-1-var-9-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-9-out-1->var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-9-out-1->var-9-out-1\n", + "\n", + "\n", "\n", - "\n", - "\n", - "fus-0-thr-2-var-9-out-0->thr-2-var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "fus-0-thr-3-var-9-out-0->thr-3-var-9-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "var-10-out-0\n", - "\n", - "LUG\n", + "\n", + "LUG\n", "\n", - "\n", - "\n", - "var-10-out-0->fus-0-thr-2-var-9-out-0\n", - "\n", + "\n", + "\n", + "var-10-out-0->fus-0-thr-3-var-9-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "var-11-out-0\n", - "\n", - "CLF\n", - "\n", - "\n", - "\n", - "var-11-out-0->fus-0-thr-2-var-9-out-0\n", - "\n", + "\n", + "CLF\n", "\n", - "\n", - "\n", - "thr-3-var-9-out-1->var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", + "var-11-out-0->fus-0-thr-3-var-9-out-0\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-9-out-1->var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-5-var-9-out-1->var-9-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "thr-0-var-12-out-0\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "thr-0-var-12-out-0->var-12-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-0-var-12-out-1->thr-0-var-12-out-0\n", - "\n", - "\n", + "\n", + "\n", + "thr-1-var-12-out-0\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "thr-1-var-12-out-0->var-12-out-0\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-1-var-12-out-1->thr-1-var-12-out-0\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-12-out-1->var-12-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-0-var-13-out-0->var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-0-var-13-out-0->thr-0-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-1-var-13-out-0\n", - "\n", - "2\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-1-var-13-out-0->var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-1-var-13-out-0->thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-1-var-13-out-0->thr-1-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-2-var-13-out-0\n", - "\n", - "2\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-2-var-13-out-0->var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-2-var-13-out-0->thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-1-thr-2-var-13-out-0->thr-2-var-13-out-0\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-3-var-13-out-0->var-13-out-0\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "thr-3-var-13-out-1->var-13-out-1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "fus-0-thr-3-var-13-out-1->thr-3-var-13-out-1\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "thr-4-var-13-out-1->var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "fus-0-thr-4-var-13-out-1->thr-4-var-13-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "thr-5-var-13-out-1->var-13-out-1\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "fus-0-thr-5-var-13-out-1->thr-5-var-13-out-1\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1780,7 +1450,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/PNAS 2021 - Arabidopsis thaliana.ipynb b/tutorials/PNAS 2021 - Arabidopsis thaliana.ipynb index 8e53e37..cf5ba72 100644 --- a/tutorials/PNAS 2021 - Arabidopsis thaliana.ipynb +++ b/tutorials/PNAS 2021 - Arabidopsis thaliana.ipynb @@ -25,7 +25,6 @@ "import matplotlib.pyplot as plt\n", "from matplotlib.colors import LinearSegmentedColormap\n", "# Cana\n", - "import cana\n", "from cana.datasets.bio import THALIANA\n", "# Networkx\n", "import networkx as nx" @@ -67,7 +66,7 @@ "{'label': 'AG'}\n", "{'label': 'WUS'}\n", "{'weight': 0.375}\n", - "{'weight': 0.10249255952380942}\n" + "{'weight': 0.10249255952380953}\n" ] } ], @@ -116,239 +115,16 @@ "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
kk_rk_ek_r*k_e*k^{out}k_e^{out}k_e^{out} / k^{out}
node
AG96.92.10.770.2351.90.38
AP374.72.30.680.3220.80.4
PI63.82.20.640.3620.470.24
AP142.41.60.590.4161.40.23
LFY42.81.20.690.3174.80.69
TFL142.81.20.690.3152.80.57
WUS31.41.60.480.5220.910.46
FUL20.751.20.380.62100
UFO1000021.60.79
FT1000010.240.24
EMF110000320.68
AP21000020.430.22
SEP1000040.90.22
LUG0000010.10.1
CLF0000010.10.1
\n", - "
" - ], - "text/plain": [ - " k k_r k_e k_r* k_e* k^{out} k_e^{out} k_e^{out} / k^{out}\n", - "node \n", - "AG 9 6.9 2.1 0.77 0.23 5 1.9 0.38\n", - "AP3 7 4.7 2.3 0.68 0.32 2 0.8 0.4\n", - "PI 6 3.8 2.2 0.64 0.36 2 0.47 0.24\n", - "AP1 4 2.4 1.6 0.59 0.41 6 1.4 0.23\n", - "LFY 4 2.8 1.2 0.69 0.31 7 4.8 0.69\n", - "TFL1 4 2.8 1.2 0.69 0.31 5 2.8 0.57\n", - "WUS 3 1.4 1.6 0.48 0.52 2 0.91 0.46\n", - "FUL 2 0.75 1.2 0.38 0.62 1 0 0\n", - "UFO 1 0 0 0 0 2 1.6 0.79\n", - "FT 1 0 0 0 0 1 0.24 0.24\n", - "EMF1 1 0 0 0 0 3 2 0.68\n", - "AP2 1 0 0 0 0 2 0.43 0.22\n", - "SEP 1 0 0 0 0 4 0.9 0.22\n", - "LUG 0 0 0 0 0 1 0.1 0.1\n", - "CLF 0 0 0 0 0 1 0.1 0.1" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "ZeroDivisionError", + "evalue": "float division by zero", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 8\u001b[0m\n\u001b[1;32m 1\u001b[0m pd\u001b[38;5;241m.\u001b[39moptions\u001b[38;5;241m.\u001b[39mdisplay\u001b[38;5;241m.\u001b[39mfloat_format \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{:.2g}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mformat\n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m#\u001b[39;00m\n\u001b[1;32m 3\u001b[0m df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame({\n\u001b[1;32m 4\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnode\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39mname \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 5\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39mk \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_r\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39minput_redundancy(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39meffective_connectivity(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[0;32m----> 8\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_r*\u001b[39m\u001b[38;5;124m'\u001b[39m:[\u001b[43mn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minput_redundancy\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnorm\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 9\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e*\u001b[39m\u001b[38;5;124m'\u001b[39m:[n\u001b[38;5;241m.\u001b[39meffective_connectivity(norm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m) \u001b[38;5;28;01mfor\u001b[39;00m n \u001b[38;5;129;01min\u001b[39;00m T\u001b[38;5;241m.\u001b[39mnodes],\n\u001b[1;32m 10\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m:[v \u001b[38;5;28;01mfor\u001b[39;00m n,v \u001b[38;5;129;01min\u001b[39;00m EG\u001b[38;5;241m.\u001b[39mout_degree()],\n\u001b[1;32m 11\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m:[v \u001b[38;5;28;01mfor\u001b[39;00m n,v \u001b[38;5;129;01min\u001b[39;00m EG\u001b[38;5;241m.\u001b[39mout_degree(weight\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mweight\u001b[39m\u001b[38;5;124m'\u001b[39m)],\n\u001b[1;32m 12\u001b[0m })\u001b[38;5;241m.\u001b[39mset_index(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnode\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 13\u001b[0m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m / k^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk_e^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m/\u001b[39m df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk^\u001b[39m\u001b[38;5;132;01m{out}\u001b[39;00m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 14\u001b[0m df\u001b[38;5;241m.\u001b[39msort_values(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mk\u001b[39m\u001b[38;5;124m'\u001b[39m,ascending\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,inplace\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", + "File \u001b[0;32m/data/siyer/CANA/cana/boolean_node.py:222\u001b[0m, in \u001b[0;36mBooleanNode.input_redundancy\u001b[0;34m(self, operator, norm)\u001b[0m\n\u001b[1;32m 218\u001b[0m k_r \u001b[38;5;241m=\u001b[39m \u001b[38;5;28msum\u001b[39m(redundancy) \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m2\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mk\n\u001b[1;32m 220\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m norm:\n\u001b[1;32m 221\u001b[0m \u001b[38;5;66;03m# Normalizes\u001b[39;00m\n\u001b[0;32m--> 222\u001b[0m k_r \u001b[38;5;241m=\u001b[39m \u001b[43mk_r\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mk\u001b[49m\n\u001b[1;32m 224\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m k_r\n", + "\u001b[0;31mZeroDivisionError\u001b[0m: float division by zero" + ] } ], "source": [ @@ -371,7 +147,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -416,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -439,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -451,14 +227,14 @@ " scc = [len(cc) for cc in nx.strongly_connected_components(G)]\n", " return len(scc), scc\n", "#\n", - "def SortedCounter(l):\n", - " c = dict(sorted(Counter(l).most_common(), reverse=True)) \n", + "def SortedCounter(L):\n", + " c = dict(sorted(Counter(L).most_common(), reverse=True)) \n", " return c" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -492,7 +268,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -504,7 +280,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -533,7 +309,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -949,14 +725,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -1411,7 +1187,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1721,7 +1497,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/tutorials/PNAS 2021 - ER+ Breast Cancer.ipynb b/tutorials/PNAS 2021 - ER+ Breast Cancer.ipynb index 53d2e2e..4f1db0a 100644 --- a/tutorials/PNAS 2021 - ER+ Breast Cancer.ipynb +++ b/tutorials/PNAS 2021 - ER+ Breast Cancer.ipynb @@ -22,8 +22,6 @@ "from collections import Counter\n", "import graphviz\n", "# Cana\n", - "import cana\n", - "from cana.boolean_network import BooleanNetwork\n", "from cana.datasets.bio import BREAST_CANCER\n", "# Matplotlib\n", "import matplotlib as mpl\n", @@ -296,8 +294,8 @@ " scc = [len(cc) for cc in nx.strongly_connected_components(G)]\n", " return len(scc), scc\n", "#\n", - "def SortedCounter(l):\n", - " c = dict(sorted(Counter(l).most_common(), reverse=True)) \n", + "def SortedCounter(L):\n", + " c = dict(sorted(Counter(L).most_common(), reverse=True)) \n", " return c" ] }, @@ -7478,7 +7476,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXYAAAB7CAYAAABgt6sPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlyklEQVR4nO3deVgT9/o28CeZsCeyr0EWhZCFRcGDyqKoaKUttkdqsbVF8bigXWxd0GP9qRdSt5ZaES20nCrQulRpUemitSIUtx4Q2UIIYBEIhJ0QCASyvH94wgsICIoi8flcl3/IJDOTzOTO5JuZOySlUgkIIYTUB3msVwAhhNDowmBHCCE1g8GOEEJqBoMdIYTUDAY7QgipGQx2hBBSMxjsCCGkZjDYEUJIzWCwI4SQmsFgRwghNYPBjhBCaoYy0jtkZ2ebUSiUeABwBnxjQAihsaAAgAKZTLbKw8Ojrv/EEQc7hUKJt7CwYJmamjaTyWRsEEMIoWdMoVCQ6uvr2UKhMB4AFvWf/jhH3M6mpqatGOoIITQ2yGSy0tTUVAQPRk4env5488RQRwihsfS/HB4ww8flGDlBEB5MJpPt6OjImTt3rkNDQwPh6urKZDKZbEtLSxdDQ0M3JpPJZjKZ7OLiYk06ne5SU1NDAQD4888/del0usv169d1hrOsqVOnMkd7/VNTU2lz5sxxAAD4/vvv9bdv324x2stQF4mJiQYkEskjJydHW/W34uJiTUdHR47q/1FRUSYTJkyY4uTkxGYymWwNDQ13BoPBZjKZ7PXr19OfdB22bdvWs336LxuNvYH2kdESHR1tXF5ervE49z148KBpTEyM8Wiv03CMeIy9P2sLczdBbd0Tz0eFbm4mqxLW5g51Gy0tLQWPx+MCACxevNjus88+M83Ly+MBPNgQWVlZeomJiRX973f79m2dpUuXTv7uu+/KvL29O4azPjk5ObzHeRzDtWzZMhEAiJ7mMkaDBd3Krba6ZtS2s7mVpUwoqB5yOwMAnD592sjd3b0tKSnJaOrUqdX9px89etQoLi7OrLi4uMDS0lIGAECn013S09P5qv8/qejoaMv9+/cLR2Ne6syKbu5WUz16WWBpZSarFgydBQCP3keexHfffWcyZcqUDjs7u+6R3jc8PLx+NNdlJJ54Iwhq6yiiT8NGY10AAED/k9gRrdOMGTPa8/LyHnn0nZubq71q1Sr7b7/99u85c+ZI+k/PysrSDg0Nte/u7iYpFApITk4uc3Fxkerq6k6VSCQ5crkcli9fbnPr1i3axIkTpQqFAlasWNEYGhraTKfTXd58883GS5cu6ctkMtKZM2fuTZ06tTMtLU1348aNNp2dnWRtbW3FiRMn/nZzc5P2Xm7vN6KgoCA7Go0mz83N1auvr9fYs2dPVWhoaPNQyx7Jc/UkaqtrKIfyM0dtfh+7+DxyO4tEInJWVhb1ypUrxa+99prDF1980edFGx8fb3jo0CHLq1evFg83xKOjo43Pnz9v0NXVRa6srNQKCgpqjIqKqgEA8Pf3n1xTU6MplUrJYWFhtZs3b25Yv349XSqVkplMJpvBYHR89tlnArlcDkuXLrXNysqimpubd126dKlUJBIRCxYscCwsLCy6efOmjpeXF5vP5+c7Ojp2TZw40ZnL5XIvXrxI279/v2V3dzfZ0NBQdubMmXtWVlaySZMmOd+8eZNnZWUlk8vlYG9v73z79m3eaL0xPSs11XWUi6VrRm1+gQ5fP9Y+kpqaStu9e7eVoaGh7N69e9rTp08XJyUlVRAEAXFxcUZRUVEWSqWS5O/v3/LVV18JAAB0dXWnLlu2rP769es0fX19eXJy8r1Lly7RCgoKdENCQiZpa2srsrKyiv744w/qtm3bJsrlcnBzc5MkJibe19HRUa5fv55+6dIlA4IglH5+fq1ff/111caNG62oVKo8IiKiNjIy0uz48eOmBEEoGQxGZ2pq6r1Re6IGMC6HYlRkMhmkpaXRXn/99ZZH3TY4ONghKiqq4qWXXmobaPqRI0dM169fX8vj8bh5eXlF9vb2Xb2nJyYmGlZWVmoWFxcXJiQklOfk5FB7TzcxMZFxudyilStX1u/fv98cAMDNza3zr7/+4hUVFXF37dolCA8Pt37UetbW1mpkZWXxzp8/X7Jr1y76cJatrr7//nsDPz8/kaurq9TAwECemZmpq5pWXV2tGR4ebvP777/zbWxsRhSAeXl5emfPnr1XUFBQeOHCBaOMjAzd/y2vvLCwsOju3bvcuLg4c6FQSBw7dkyg+oR44cKFvwEAKioqtD/88MO60tLSQn19fXliYqIhnU6XSaVSclNTEzktLY3K4XAkV65cofL5fE1jY2MZjUZTzJ8/v+3u3bu8oqIi7htvvNEUERFhQRAEvPHGG43x8fFGAADnz5+fwGKxOsZbqI+VwfaR/Px8vcOHD1cWFxcXlpeXayUmJhqWl5dr7N69m37t2jU+l8stzMnJ0UtKSjIAAOjo6CC7u7tLuFxukbe3t3jbtm1WoaGhzc7OzpLExMR7PB6PSyaTYe3atfZnzpwp4/P5XJlMBp999plpbW0t8csvvxiWlJQU8vl87t69e2v6r2d0dLRFQUEBl8/nc0+cOHH/aT8v4zLYVUdQhoaGU1paWiivv/5666Pu4+3t3fqf//zHRCYb+PUyc+bM9qioKMtPPvnEoqSkRJNKpfb5gvjPP/+kLl68uJkgCLCxsZHNmDFD3Hv622+/3QwA4OnpKamsrNQCAGhqaiJefvnlyY6Ojpzw8PCJfD7/kWOAixYtaiEIAjw8PDobGxs1hrNsdfXDDz8YvfXWW80AAEFBQU1JSUlGqmmGhoYyKyurrsTERMORztfHx6fVwsJCTqVSla+88krztWvXqAAABw4cMHdycmJ7eHiwhEKhRmFh4YDbi06nS728vDoAAKZOnSopLy/XAgCYNm1a25UrV6iZmZm08PDwmj///JN25coV6owZM9oAAP7++29NX19fRwaDwY6Ojrbg8Xg6AADr1q1rOH36tDEAwLfffmuyYsWKhpE+phfVYPuIi4tLO5vN7qJQKPDmm282/fnnn9TMzEy9GTNmiK2srGQaGhoQHBzclJ6eTgUAIJPJsGrVqiYAgJUrVzb+9ddfDx085ebmaltbW0tdXV2lAAArVqxozMzMpBkZGcm1tLQUS5cutU1ISDCgUqmK/vd1cnLq+Oc//2l/7NgxIw0Njad+8sm4DHbVEVR5eXl+V1cXaf/+/WaPus8333xTAQAQEhJiO9D0sLCwpvPnz5fq6OgoAgICGBcuXKD1nv6oH/3W1tZWAgBQKBSlTCYjAQBs3bqVPnv2bHFJSUnhxYsXS7u6uh75fKvm03uZL+IPjguFQuLWrVsT3nvvPVs6ne4SExNjceHCBUOF4sFrRkdHR3H58uWS48ePm3311VdGj5hdHyQS6aH/p6am0tLT02lZWVm84uJiLovF6ujo6Bhwe2lqavZsEIIgera3j49PW0ZGBq2qqkpz2bJlLYWFhTqZmZnU2bNniwEA3n//fZv169fX8fl8bkxMzH2pVEoGAHBwcOg2MTGRXbhwgZaTk6O3ZMmS5/47l+fBYPuIUqkccBuP5HXU//4Ag78ONTQ04O7du0VBQUEtKSkpBn5+fo79b5OWllby3nvv1WdnZ+u5ubmxu7tHPGQ/IuMy2FWMjY3l0dHRFUePHjWXSqUPb4leyGQynD9//l5paan2Rx99ZNV/OpfL1WSxWNIdO3bULViwoOXu3bt9xu19fX3bUlJSDOVyOVRWVlJu375N6z+P/lpbWwlra+suAIC4uDiTkT6+J1n2eJeUlGS4ePHixurq6nyBQJAvFArzrK2tuy5fvtxzJGVlZSX77bff+Hv27KEnJydPGO68MzMzJ9TW1hJtbW2kX375xWD27NltLS0thL6+vpxGoylycnK0c3Nz9VS3p1AoykftXwAA8+fPFycnJxvZ29tLCYIAAwMDWVpamr6/v38bAIBYLCZsbGy6AQBOnDjR52yJlStX1q9atcp+0aJFTRTKqH3/qNYG20cyMjKo+fn5ejweT1Mul8O5c+eMfH19xbNmzWq/ffs2raamhiKTyeDs2bNGfn5+bQAACoUCjh8/bgjwYNt4enqKAQCoVKpcJBIRAABTpkzpFAgEmgUFBVoAAImJica+vr5ikUhEbmpqIoKDg0WxsbGVRUVFur3XUy6XQ1lZmWZgYKD42LFjVWKxmFDN82kZ18EOAODt7d3BYrE64uPjH/mRXEdHR/nrr7+W/vbbbwb79u0z7T0tKSnJiMFgcJhMJrukpER77dq1jb2nL1++vNnS0rKLwWBwQkNDbd3c3NoNDAzkQy1v69atwt27d1u7u7sz5fIhbzqkx1n2eHf27FnjxYsX9/ly+LXXXmvuPRwDAMBkMruSk5NL161bZ3f16lU9GIZp06a1BQcH2zs7O3MCAwObZ82aJQkKChLJZDISg8Fgb9++3crNza1ddftly5bVs1gs9qJFi+yHmq+Tk1MXAICvr68YAGDmzJltNBpNbmpqKgcA+OSTT6rfeuutyR4eHk7GxsZ9xgTfeustkUQiIdasWdP48JzRQAbbR5KTk42mTJnStmnTJmsGg8GxsbGRvvvuuy22trbdO3fuFMyePZvBYrE4rq6uknfeeacF4MEnwMLCQh0Oh8PKyMig7du3rwYAICQkpOGDDz6wZTKZbIVCAbGxseVLliyZzGAw2GQyGTZv3lzf0tJCLFy40JHBYLB9fX2dIiMjK3uvk0wmI7399tv2DAaD7ezszF67dm2tiYnJU339kkb6MT83N7fczc2tZwxwLE53HCsikYisr6+vEAqFxD/+8Q/W9evXeSP94m48Lhtg7E53HG1DnQ47ljIyMnQ//vjjidnZ2cVjvS6Pa6xOd+wvNTWVFhUVZZ6WllY63Puozn4b6bLGWm5urombm5td/78/8UZ4XkP4aZg/f75ja2sr0d3dTdqyZUvNswzWsVw2AMBYhPCLYvv27RYnTpwwPX78+N9jvS5P4nFCGD0dT3zEjhBCaGwMdsQ+7sfYEUII9YXBjhBCagaDHSGE1AwGO0IIqZlxGey9a3sDAgImicViMsCDU5YAAPh8viaHw2ExmUy2g4MD5+DBgz3nrHt6ejqpukGKi4s1bW1tnUdycctgIiIizFTr0Xtd0NNz+PBhY1U980BVvUlJSQYMBoNtb2/PYTAYbFUvCABAUFCQHZ1Od2EymWwnJyf2+fPney76SktL0502bZqTnZ2ds729PSc4ONhWLBaTc3JytKdMmcLU1NR037lzp/loPY6kpCSD7OzsnvqC3vsoGtpgWTAcg9VnV1dXU1xdXZksFov922+/PXEvU//t+9FHH1mlpKQ81YsMn/h0RwtLK7da4Sie32xhKRPWDH1qXe/a3kWLFtlHRUWZ7t69u1Y13cbGpjsrK4uno6OjFIlEZDabzXnzzTdbeldvlpWVabz00kuMvXv3VgYFBT2ya+ZR4uLizFevXt1Eo9Ee6olQB9ZW5m6CmlG8XsHSTFZV/WSnx23YsKFxw4YNjQAPV/XevHlT55NPPrG+fPkyn8lkdvF4PM0FCxYwGAyGdPr06R0AAJGRkVWhoaHNFy9epL3//vu2r732WkFlZSVl2bJlkxMTE+/5+/u3KxQKSEhIMGxpaSGbmZnJDh8+XHHu3LkR99MMJSUlxUAmk4k8PDw6R3O+z5qVFd2tpqZ69M5jt7SSVVcLnigLZDIZDOdK3t712ampqTQHB4fOH3/8sXy46zrUcvpv3y+//HJUq4UH8sQboVZYQ9l+8r+jsS4AALD37X+MaJ18fHza+tf29u5b6ejoIKn6RVQEAoFGaGio/c6dOwX/26B9DFX7uWzZMpvc3Fy9zs5OcmBgYPOhQ4eqIyMjzerq6jRmz57NMDQ0lN2+fZsPAPDBBx/QL1++rK+tra1ITU0ttbS0lNnZ2blUVFTkNzU1EWZmZlN+/vnn4oCAgDYPDw+nhISE8vr6emKgql8PDw+nI0eOVKjKp9zd3ZlfffXVfVVIPW2CmjqK8tL7ozY/0ksxQ27n4uJizYULFzp6enq23blzh8pisSQrV65siIiIoDc2NlJOnDhxb6D6ZZUDBw5YbNy4sYbJZHYBPLhC9eOPPxbu27fPIiUlpc/54vPmzWurq6vTAACIiooye/PNNxv9/f3bAR5UUfSuR6bT6bLz588bDLXuA1XAWllZyaKiokyOHz9u2t3dTbKzs5OeO3fu71u3bulcuXLF4NatW7QDBw5YJicnlwEAnDp1yvC9996zFYvFRGxsbPnChQvbZs+e7XDw4EHB9OnTO1gsFvuVV15p/vzzz2s2bNhgZWtr2/Wvf/2raeHChQ4ikYiQyWSknTt3Vr/zzjstGzZssDIxMZH93//9Xx3Ag/3S3Ny8e8eOHQ/9CPKTqKmppqRdGb3rq+b4Oz1WFqSmptL27NljaWZm1s3lcnXz8/O5ISEhtnl5eboEQcDBgwcrAwMD+xTpqS5cCwsLq9+1a5d1Z2cnmclksrOysoouX75Mi4iIsOrq6iLZ2tpKT58+Xa6vr6+g0+kub731VkNaWtqEtWvX1onFYmI423fnzp2Wr776qig0NLT5/PnztIFqgAerAh/uczEuh2JUuru74dKlSxNcXFweCrfS0lKN/30Md/3www+FvY/Ww8LC7FevXl23cuXKQfvMB6r9BAD44osvBAUFBUU8Hq/w+vXrtNu3b+vs2LGjzszMrDs9PZ2vCvWOjg7yzJkz24qLi7kzZ85sO3LkiCmFQgF7e/vOO3fuaP/+++9UNpstuXbtGrWjo4MkFAo1nZ2dpYNV/a5YsaIhPj7eBAAgLy9Pq6uri/SsQn2sVFZWam/atKmOx+MVlpWVaX///ffGWVlZvE8//bTq008/tRzqvnw+X3v69Ol9gn/GjBntAzVsJicn6/v7+7cAAHC5XJ1p06YN+oYxHANVwAIALFu2rLmgoKCouLiY6+Tk1BEdHW0yf/78dn9//5bIyMgqHo/H5XA4UoAHl6Hn5+cXHThwoDIiIsIKAMDb27vt6tWr1KamJjJBEMpbt25RAQBu3bpFnTdvnlhXV1fx888/l3K53KL09HT+9u3brRUKBaxfv77h1KlTxgAPektSUlIMV61apVbVBf2zIC8vT++zzz4TlJWVFR44cMAMAIDP53NPnjx5b82aNXYSiWTA7h8vL6+Of//739WBgYHNPB6PKxaLib1791pmZGTwuVxukbu7u2TPnj09w3Da2tqK7Ozs4jVr1jSPZPsCAEgkEtJANcCq6QNVgQ/XuAx2VW2vi4sL29raumvDhg0PXTDl4ODQzefzuUVFRQUnT540qays7Hn39/b2bj19+rTxUONxA9V+AgAkJCQYsdlsFpvNZpeUlGjn5uYOWO2qoaGhXLp0qQgAwMPDo/3+/fuaAABeXl7iP/74g5aenk7bsmVLzc2bN2kZGRl6qm6Swap+V6xY0XzlyhV9qVRKio2NNXn77bfV/iIxOp0u9fT07CAIAhgMRsfcuXNbyWQyuLu7S6qqqrSGuq9SqSSRyeT+f+vT2rdjxw5ra2trl7Vr19rv3LnzoQ7txzVYBWx2draOh4eHE4PBYCcnJxsPVgsMALBkyZJmAAAvL6/2qqoqTQAAPz8/cWZmJu3333+nLViwQCSRSAixWEyuqqrScnNzkyoUCtJHH31kzWAw2HPmzGHU1dVpVlVVUZycnLoMDAxk169f1/npp58mcDgciYWFhVp0DQ2WBa6uru2qT2s3btyghoSENAIATJ06tdPKyqorPz9/WD+jd+3aNb2ysjJtT09PJpPJZJ8+fdq4oqJCUzU9JCSk5+BwJNsXYPAaYNX0garAh2tcBrtqXI3H43ETEhIqew+99GdnZ9ft5OTUceXKlZ4nbNu2bUJ3d/f2wMDASYPVZw5U+8nj8TRjYmLM09PT+Xw+nzt37lxRZ2fngM8hhUJRqoKFQqGAqtrVz8+vLTMzk3rnzh29JUuWiFpbW4k//viD5uPjIwYYvOqXRqMpfH19W0+ePGlw4cIFo3/9619NI3rSxqHe9bhkMrlniI0gCJDL5UO2LTIYjI6bN2/2+QLyr7/+0nV0dOz5OBsZGVl1//79/G3btglWrFhhDwDAYrE6srKyRvWLS9W+tGbNGvuYmJgKPp/P3bp1a7WqtncgvWqgex7rrFmzJHl5eboZGRlUPz8/sbOzs+TLL780cXFxaQcAiIuLM2psbKTk5+cX8Xg8rrGxcbeqejg0NLQhPj7e5Pjx4yahoaFqc7Q+WBbo6ur2jL8+Se21UqkEHx+fVtUyysrKCn/44YeeH8ro/Z3aSLbvcNZroCrw4RqXwf4oZWVlGm1tbSQAgPr6eiIrK4vK4XD6jE/Fx8dX0mg0eXBwsF3/MXiAB0Mx/Ws/m5ubCR0dHYWRkZG8srKScu3aNX3V7fX09OQikeiRz6efn1/7nTt3qGQyWamrq6vkcDiSxMRE0zlz5rQBDF31GxYW1rB169aJbm5u7ebm5mpxxPW0bN26VXjo0CHL4uJiTYAHY/ZffPGFZXh4eJ/fLiUIAnbs2FGnUChIycnJEzZv3lz3ww8/GPduijx27JhRRUXFsMd7B6uAlUgkZBsbm26pVEo6ffp0T0sllUqVt7a2Dqur39LSsvvChQuGc+bMaff19RUfPXrUwtvbuw0AQCQSESYmJt1aWlrKixcv0qqrq3uOLN99992WtLQ0/dzcXL2goKAXqu/dx8en7bvvvjMCeDCMWVNTo+nq6jqs8Wo/P7/2rKwsqqqqVywWk/Py8gY8eh7p9h2sBvhxHmN/ahnseXl5Ou7u7iwnJye2t7e30/vvvy/09PTsMx5NJpPh7Nmz5bW1tRrr1q176CfrBqr9nDlzZoezs7PE0dGR8+6779p5eHj0/Mze8uXLGwICAhynT5/OGGrddHR0lBYWFl3Tpk1rB3jQtd7e3k5Wrd9QVb++vr4SPT09eWhoqNoPwzwpLy+vjoiIiKrAwEAHe3t7TmBgoMOePXuqVF8+90Ymk2Hr1q3Vn3/+ucXEiRNliYmJ97Zs2WJtZ2fnPGnSJE5mZibN0NBQUVFRQTE3N3f9+uuvzQ8dOmRpbm7u2tTU9NBraLAK2G3btlV7enqyfH19Gb0/OSxbtqwpOjragsVisQsLC4f8yD1z5kyxiYlJz0/t1dbWaqgOClatWtWUm5ur5+zszPruu++M7O3te5ahra2t9PLyan0R+97Dw8Pr5HI5icFgsIODgyfHxcWV6+joDOsw3srKShYXF1e+dOnSSQwGg+3h4cEcbBhnpNtXV1dXOVAN8JM/4lEoARuL0x2ftsep/XwWysvLNfz8/JzKysoKCOKp9vQ/5Hk83fF59TxWwMrlcuBwOOyzZ8+Wubi4SB99j5Ebi9MdX3RPrbZ3rEP4RRETE2McGRlJ37t3b+WzDnUAAHUN4RdBdna29muvveYYEBDQ/LRCHQAAQ/j5gbW9CCE0TmFtL0IIvSAw2BFCSM1gsCOEkJrBYEcIITUzLoOdRCJ5vP766/aq/3d3d4OhoaGbqoJTZd68eZOnTJnC7P23jRs3WpmZmbmqqj6///57fdXfVVWsEomE5OXl5bhp06Yh+0iGAytZH5+qklX1T1Wr6unp6WRnZ+fs5OTEdnZ2Zt24cUPnUfNSOXjwoGlMTIzxaK9r7+06e/Zsh4aGhmd/6tILSLWPODg4cJycnNi7d+8273/9x4voiU93tLa2dBMIhKN3fjPdQlZVVTPkaVM6OjqK4uJinba2NhKVSlX+9NNPE8zNzft0AzQ0NBCFhYV6urq6ch6Pp6nqjQAACAsLq42IiKi9c+eO9rx585yWLl3as7zOzk7Syy+/PHnKlCmSqKioJ+4PUZdKVjqd7lZdPXrnKFtZWckEguFXsvaXmJh4b9asWZLDhw8bb9682frGjRslw1lueHj4qFwAMpT09PTn6vqHZ4Vuae1WLRSM3j5iQZcJaqqGvY8IBALKkiVLJolEIuLQoUN9qnG7u7tBQ0NjtFbtuffEG0EgEFKUyh9HY10AAIBEWjysdZo3b57o7NmzBqGhoc2nTp0yCgoKarpx40ZPKX5SUpKhv79/i7m5eXdCQoLRvn37hP3n4e7u3kkQBAiFD96YZDIZadGiRZMmTZokPXbsmGCg5b6olazV1dWU/Pz8UZufi4vLqATArFmz2qOjoy0GmrZ+/Xr6pUuXDAiCUPr5+bV+/fXXVRs3brSiUqnyiIiI2vT0dN3Vq1fb6erqKqZPn9529epV/ZKSksLo6Gjj1NRUg46ODnJFRYVWQEBAS2xsbBUADFjb3H+5dDrdJSsrq6i1tZUcEBDg6Onp2ZaVlUU1NzfvunTpUimVSlUOtuzReE7GSrVQQMmLe/xelv5c15JGtI/Q6XRZfHx8uZeXFzsqKqo6JibG+Ndff9WXSqVkiURC3rFjR03vCw9DQkJspk2b1v7hhx82njlzRn/btm3WRkZGMhcXF8n9+/e10tLSSn/++Wfqpk2bbAAedP7cuHGDZ2ho+Nz/5sK4HIoBAHj33Xebzpw5YyiRSEhFRUW6M2fObO89/ezZs0bvvPNO0/Lly5uSk5ONBprH1atX9chkslL14wxHjx61oFAoym+//bZysOViJeuzo2ruU/375ptvHvqBi4sXL04ICAho6f/32tpa4pdffjEsKSkp5PP53L179z706WvVqlX2R48evX/37l0eQRB9EonL5eqmpKTcKyoqKrxw4YJhaWmpBsDAtc1DPYaKigrtDz/8sK60tLRQX19frqp/HmrZ6PGx2ewuhUIBAsGDTw537tyhnjp16u9bt27xB7uPRCIhbdiwwfbXX38tyc7OLm5sbOx5Q4mKirKIjo6+z+PxuLdu3eJRqdTnPtQBxnGwT58+vaOqqkrrm2++MfL39+9TalRZWUm5f/++1oIFC9pcXV2lFApF+d///rdnnDs2NtacyWSyt2zZYp2YmHhP1cLo4eHRdufOHepgJT8AWMn6LPVu7uPxeNzVq1f3VKSGhIRMMjc3dz1y5IjFli1bHvp0YmRkJNfS0lIsXbrUNiEhwaD/C7KhoYFob28nz58/vx0AYPny5X3aMn18fFqNjY3lurq6SgcHh86ysjItgOHXNqvQ6XSpqp9m6tSpkvLycq1HLRs9md4XXfr6+rY+qjDv7t272hMnTpSqhmuXLl3asz1mzJjRtnnz5omRkZFmDQ0NxHgZzhm3wQ4AsHDhwpZdu3ZNDAkJ6fPCSEhIMGptbSUmTpzoQqfTXQQCgVZSUlLPUXtYWFgtj8fjZmdnFy9cuLCnyMvHx0e8f//+ildeecWxvLx8WFsQK1nHRmJi4r2Kior8119/vWn16tU2/adraGjA3bt3i4KCglpSUlIM/Pz8HHtPf9QV170rgwmCUHZ3d5NGUts82HxkMtmIr/ZGw8flcjUJggA6nS4D6Fvfq6Ghoezd5CqVSkkAQ+8Le/fuFcbHx9/v6Ogge3l5sXJycobV4z7WxnWwr1u3rmHTpk3V/Zsbz507Z/TTTz+VCASCfIFAkH/79m1uSkrKgMMx/a1YsaLlgw8+qF2wYIHjQGc2YCXr80NLS0t56NAhwd27d/Xu3LnT5wUnEonITU1NRHBwsCg2NrayqKioz5lIpqamcj09PcUff/yhBwDQ+41/MEPVNo/E4ywbPVp1dTVl9erVtqGhoXX9f2QFAGDy5MnS0tJSnY6ODlJjYyORmZk5AQDAzc2ts7KyUktV8XzmzJme7VFYWKjl6enZ8emnnwpdXFzaCwoKxkWwj+v+zsmTJ3ervjRUKS4u1qyurtacO3duz5g7k8nsolKp8t4d20MJDw+vFwqFGgsXLnTIyMjg6+rq9ryl96pktaDRaPIff/zxHsD/r+yk0+ldLBZL0tbWRgA8qOxct26dXWxsrPm5c+fKhlruzJkzxRkZGRNUlaxr1qzpU8kaEBDg4OzszOJwOJKBKlkNDAzk6lTJqhpjV/1/7ty5ov5falOpVOW6detq9+/fb977BxBaWlqIV1991UF1VBYZGfnQ9yZxcXHlYWFhtrq6ugpvb28xjUYb8iN779pmGxsbae/a5pEa6bLRwFT7iEwmIxEEoQwODm7ctWtX7UC3dXBw6A4MDGxmsVgce3v7Tg6HIwF4sA998cUX9xcuXOhoZGQkmzp1ak92HDx40OzGjRsTyGSyksFgdLzxxhvj4sDpiUvAxuJ0x7H0olayjsXpjk+bSCQi6+vrKwAAtm/fblFTU6Nx/PjxQb84V5dlPy1jcbrjaFFtD4VCASEhITaOjo6du3btGtUzy56Gp1bb+zyH8IvgWVWyjnUIPw0//PCDflRUlKVcLifR6XTpyZMny1+EZT8tzyqEn4Yvv/zS5NSpUybd3d0kDocj2bhx47husMXaXoQQGqewthchhF4QjxPsCoVCMaJfzEYIITS6/pfDA14w9TjBXlBfX6+P4Y4QQmNDoVCQ6uvr9QGgYKDpI/7yVCaTrRIKhfFCodAZcCgHIYTGggIACmQy2aqBJuJVcAghpGbwiBshhNQMBjtCCKkZDHaEEFIzGOwIIaRmMNgRQkjNYLAjhJCawWBHCCE1g8GOEEJqBoMdIYTUDAY7QgipGQx2hBBSMxjsCCGkZjDYEUJIzWCwI4SQmsFgRwghNYPBjhBCagaDHSGE1AwGO0IIqRkMdoQQUjMY7AghpGYw2BFCSM1gsCOEkJrBYEcIITWDwY4QQmoGgx0hhNQMBjtCCKkZDHaEEFIzGOwIIaRmMNgRQkjNYLAjhJCawWBHCCE1g8GOEEJqBoMdIYTUDAY7QgipGQx2hBBSMxjsCCGkZjDYEUJIzWCwI4SQmsFgRwghNYPBjhBCagaDHSGE1AwGO0IIqRkMdoQQUjMY7AghpGYw2BFCSM1gsCOEkJrBYEcIITWDwY4QQmoGgx0hhNQMBjtCCKkZDHaEEFIzGOwIIaRmMNgRQkjNYLAjhJCawWBHCCE1g8GOEEJqBoMdIYTUDAY7QgipGQx2hBBSMxjsCCGkZjDYEUJIzfw/Y3eNBs8uzIwAAAAASUVORK5CYII=\n", + "image/png": "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", "text/plain": [ "
" ] @@ -7535,7 +7533,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.12.3" } }, "nbformat": 4, From 36cd7a79551ce297d3b15022c99805ccc96bcb5c Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 3 Jun 2024 15:57:04 -0400 Subject: [PATCH 02/14] partial lut and test --- cana/drawing/plot_look_up_table.py | 125 +++++++++++++++++++++++++++++ cana/utils.py | 51 ++++++++++++ tests/test_boolean_node.py | 19 +++++ 3 files changed, 195 insertions(+) create mode 100644 cana/drawing/plot_look_up_table.py diff --git a/cana/drawing/plot_look_up_table.py b/cana/drawing/plot_look_up_table.py new file mode 100644 index 0000000..1fd08dc --- /dev/null +++ b/cana/drawing/plot_look_up_table.py @@ -0,0 +1,125 @@ +import matplotlib.pyplot as plt +from matplotlib.text import Text +from matplotlib.patches import Rectangle +from matplotlib.collections import PatchCollection +from IPython.display import display + + +def plot_look_up_table(n): + """ + Plot the Look-Up Table of a BooleanNode + + Parameters + ---------- + n : BooleanNode + The BooleanNode to plot the Look-Up Table + + Returns + ------- + None + """ + + # Init values from BooleanNode + k = n.k if n.k>=1 else 1 + inputs = n.inputs if not n.constant else [n.name] + inputlabels = [n.network.get_node_name(i)[0] if n.network is not None else i for i in inputs] + LUT = n.look_up_table().sort_index(ascending=False) + # Count number of F in the LUT + n_fs = LUT.shape[0] + # Schemata Cell Width and spacing + cwidth = 60. + cxspace = 0 + cyspace = 6 + border = 1 + sepcxspace = 21 + # sepcyspace = 15 + dpi = 150. + # Margins + top, right, bottom, left, hs = 120, 25, 25, 60, 25 + # Axes Width & Height + ax1width = ((k*(cwidth+cxspace))+sepcxspace+(cwidth)) + ax1height = (n_fs*(cwidth+cyspace)-cyspace) + # Figure Width & Height + fwidth = (left + ax1width + hs + right) + fheight = (bottom + ax1height + top) + # Percentages for Axes location + _ax1w = ((ax1width*100) / fwidth) / 100 + _ax1h = ((ax1height*100) / fheight) / 100 + _bottom = ((bottom*100) / fheight) / 100 + _left = ((left*100) / fwidth) / 100 + _hs = ((hs*100) / fwidth) / 100 + # Init Figure + fig = plt.figure(figsize=(fwidth/dpi,fheight/dpi), facecolor='w', dpi=dpi) + ax1 = fig.add_axes((_left,_bottom,_ax1w,_ax1h), aspect=1, label='LUT') + + ### LUT Plot ### + + yticks = [] + patches = [] + x,y = 0.,0. + # + for i,r in LUT.iterrows(): + ins = str(r['In:']) + out = r['Out:'] + x = 0. + xticks = [] + for input in ins: + if input == '0': + facecolor = 'white' + textcolor = 'black' + elif input == '1': + facecolor = 'black' + textcolor = 'white' + text = '{label:s}'.format(label=input) + ax1.add_artist(Text(x+cwidth/2,y+cwidth/10*4, text=text, color=textcolor, va='center', ha='center',fontsize=14,family='serif')) + r = Rectangle((x,y), width=cwidth, height=cwidth, facecolor=facecolor, edgecolor='black') + patches.append(r) + xticks.append(x+cwidth/2) + x += cwidth + cxspace + + x += sepcxspace + r = Rectangle((x,y), width=cwidth, height=cwidth, facecolor='black' if (out==1) else 'white', edgecolor='black') + ax1.add_artist(Text(x-(sepcxspace/2)-(cxspace/2),y+cwidth/10*4, text=':', color='black', va='center', ha='center',fontsize=14,weight='bold',family='serif')) + ax1.add_artist(Text(x+(cwidth/2),y+cwidth/10*4, text=out, color='white' if (out==1) else 'black', va='center', ha='center',fontsize=14,family='serif')) + patches.append(r) + xticks.append(x+cwidth/2) + yticks.append(y+cwidth/2) + y += cwidth + cyspace + + #y += sepcyspace + + ax1.add_collection(PatchCollection(patches, match_original=True)) + # + ax1.set_yticks(yticks) + ax1.set_yticklabels([r"$f_{%d}$"%(i+1) for i in range(n_fs)[::-1]], fontsize=14) + ax1.set_xticks(xticks) + ax1.set_xticklabels(inputlabels + ['%s'%(n.name)], rotation=90, fontsize=14) + # + ax1.xaxis.tick_top() + # Remove Tick + ax1.tick_params(which='major',pad=7) + for tic in ax1.xaxis.get_major_ticks(): + tic.tick1On = tic.tick2On = False + for tic in ax1.yaxis.get_major_ticks(): + tic.tick1On = tic.tick2On = False + # Remove Border + ax1.spines['top'].set_visible(False) + ax1.spines['right'].set_visible(False) + ax1.spines['bottom'].set_visible(False) + ax1.spines['left'].set_visible(False) + # Limits + ax1.set_xlim(-border,ax1width+border) + ax1.set_ylim(-border,ax1height+border) + #ax1.invert_yaxis() + + # FileName + filename = n.name + filename = filename.replace('/','_') + filename = filename.replace(',','_') + + ## Display + display(fig) + + plt.close() + + \ No newline at end of file diff --git a/cana/utils.py b/cana/utils.py index ec9252c..e6e54f2 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -327,3 +327,54 @@ def input_monotone(outputs, input_idx, activation=1): ) return all(monotone_configs) + +def fill_out_lut(partial_lut): + """ + Fill out a partial LUT with missing entries. + + Args: + partial_lut (list) : A list of tuples where each tuple is a pair of a binary string and a value. + + Returns: + (list) : A list of tuples where each tuple is a pair of a binary string and a value. + + Example: + >>> fill_out_lut([('00', 0), ('01', 0), ('1-', 1), ('11', 1)]) + [('00', 0), ('01', 0), ('10', 1), ('11', 1)] + """ + + if len(set([len(x[0]) for x in partial_lut])) != 1: + raise ValueError('All the input entries of the partial LUT must be of the same length.') + + k = len(partial_lut[0][0]) + + all_states = {entry[0]: entry[1] for entry in partial_lut} + for entry in partial_lut: + if not all([x in ['0','1','-','#','2','x'] for x in entry[0]]): + raise ValueError('All the input entries of the partial LUT must be valid binary strings.') + + elif any([x in ['-', '#','2','x'] for x in entry[0]]): + missing_data_indices = [i for i, x in enumerate(entry[0]) if x == '-'] + table=[] + output_list_permutations=[] + for i in range(2 ** len(missing_data_indices)): + row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))] + table.append(row) + output_list_permutations.append(entry[0]) + for j in range(len(missing_data_indices)): + output_list_permutations[i] = output_list_permutations[i][:missing_data_indices[j]] + str(table[i][j]) + output_list_permutations[i][missing_data_indices[j]+1:] + del all_states[entry[0]] + for perm in output_list_permutations: + if perm in all_states and all_states[perm] != entry[1]: + # print('Clashing output values for entry:', perm) + all_states[perm] = '!' + else: + all_states[perm] = entry[1] + + for i in range(2**k): + state = bin(i)[2:].zfill(k) + if state not in all_states: + all_states[state] = '?' + + all_states = sorted(all_states.items(), key=lambda x: x[0]) + return all_states \ No newline at end of file diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index 5b9a1ec..b6a3aad 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -468,3 +468,22 @@ def test_input_symmetry_SBF(): # assert (k_s == true_k_s), f"Input symmetry simp: SBF (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 4.0 # assert (k_s == true_k_s), f"Input symmetry: SBF (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + +# Tests for partially-specified functions +def test_partial_lut(): + partial_lut = [ + [('00','1'),('01','1')], + [('0-','1'),('10','1')], + [('001','1'),('01-','1'),('1-1','0')], + [('00--', '0'), ('1--1','1'), ('11--','0')] + ] + expected_filled = [ + [('00','1'),('01','1'),('10','?'),('11','?')], + [('00','1'),('01','1'),('10','1'),('11','?')], + [('000','?'),('001','1'),('010','1'),('011','1'),('100','?'),('101','0'),('110','?'),('111','0')], + [('0000', '0'), ('0001', '0'), ('0010', '0'), ('0011', '0'), ('0100', '?'), ('0101', '?'), ('0110', '?'), ('0111', '?'), ('1000', '?'), ('1001', '1'), ('1010', '?'), ('1011', '1'), ('1100', '0'), ('1101', '!'),('1110', '0'), ('1111', '!')] + ] + for i, partial in enumerate(partial_lut): + filled = fill_out_lut(partial) + expected = expected_filled[i] + assert(filled==expected), f"Partial LUT filling failed: {filled} != {expected}" \ No newline at end of file From dd7ea15a231cd521209ad48bc3b3933011d93ebe Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Wed, 5 Jun 2024 12:26:28 -0400 Subject: [PATCH 03/14] sync relevant changes from schema expansion --- cana/boolean_network.py | 54 ++++++++++++++--- cana/boolean_node.py | 22 ++++++- cana/datasets/bio.py | 12 ++++ cana/datasets/tempy.txt | 59 +++++++++++++++++++ cana/drawing/schema_vis.py | 7 +-- ...Canalization - BioModels - Schematas.ipynb | 7 +-- 6 files changed, 140 insertions(+), 21 deletions(-) create mode 100644 cana/datasets/tempy.txt diff --git a/cana/boolean_network.py b/cana/boolean_network.py index 3df7f83..ad9d0db 100644 --- a/cana/boolean_network.py +++ b/cana/boolean_network.py @@ -174,7 +174,7 @@ def from_file(self, file, type="cnet", keep_constants=True, **kwargs): @classmethod def from_string_cnet(self, string, keep_constants=True, **kwargs): """ - Instanciates a Boolean Network from a string in cnet format. + Instanciates a Boolean Network from a string in cnet format. Args: string (string): A cnet format representation of a Boolean Network. @@ -220,10 +220,11 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): for jnode in range(indegree): logic[inode]["in"].append(int(line.split()[3 + jnode]) - 1) + # to generate with '?' output values logic[inode]["out"] = [ - 0 for i in range(2**indegree) if indegree > 0 - ] - + '?' for i in range(2**indegree) if indegree > 0 + ] # activate this for '?' output values + logic_line = network_file.readline().strip() if indegree <= 0: @@ -238,14 +239,51 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): and logic_line != "" and len(logic_line) > 1 ): + # Check for clashing entries. for nlogicline in expand_logic_line(logic_line): - logic[inode]["out"][ - binstate_to_statenum(nlogicline.split()[0]) - ] = int(nlogicline.split()[1]) - logic_line = network_file.readline().strip() + if logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] in ['?', None, 2, '-']: # assigns output value if it is not assigned + logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = int(nlogicline.split()[1]) + elif logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] == int(nlogicline.split()[1]): # if the output value is already assigned and is the same as the new output value + pass + else: # if the output value is already assigned and is different from the new output value + print("Entry clash in node ",(inode+1)," for ",{nlogicline.split()[0]}," i.e. State number: ",binstate_to_statenum(nlogicline.split()[0])) + logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = '!' + logic_line = network_file.readline().strip() + + ## to generate with Prime Implicants(PI) + # logic[inode]["out"] = [ + # '0' for i in range(2**indegree) if indegree > 0 + # ] + + # logic_line = network_file.readline().strip() + + # if indegree <= 0: + # if logic_line == "": + # logic[inode]["in"] = [inode] + # logic[inode]["out"] = [0, 1] + # else: + # logic[inode]["out"] = [int(logic_line)] + # else: + # while ( + # logic_line != "\n" + # and logic_line != "" + # and len(logic_line) > 1 + # ): + # # Check for clashing entries. + # for nlogicline in expand_logic_line(logic_line): + # if logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] in ['?', None, 2, '-','0']: # assigns output value if it is not assigned + # logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = int(nlogicline.split()[1]) + # elif logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] == int(nlogicline.split()[1]): # if the output value is already assigned and is the same as the new output value + # pass + # else: # if the output value is already assigned and is different from the new output value + # print("Entry clash in node ",(inode+1)," for ",{nlogicline.split()[0]}," i.e. State number: ",binstate_to_statenum(nlogicline.split()[0])) + # logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = '1' + + # logic_line = network_file.readline().strip() # .e = end of file elif ".e" in line: + break line = network_file.readline() diff --git a/cana/boolean_node.py b/cana/boolean_node.py index dd0817e..80d2ab6 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -110,7 +110,12 @@ def __str__(self): @classmethod def from_output_list(self, outputs=list(), *args, **kwargs): - """Instanciate a Boolean Node from a output transition list. + """ + Instanciate a Boolean Node from a output transition list. + + For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing. + + Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs. Args: outputs (list) : The transition outputs of the node. @@ -119,16 +124,27 @@ def from_output_list(self, outputs=list(), *args, **kwargs): (BooleanNode) : the instanciated object. Example: - >>> BooleanNode.from_output_list(outputs=[0,0,0,1], name="AND") + >>> BooleanNode.from_output_list(outputs=[0,0,0,'-',1], name="EG") """ id = kwargs.pop("id") if "id" in kwargs else 0 name = kwargs.pop("name") if "name" in kwargs else "x" - k = int(np.log2(len(outputs))) + k = int(np.ceil(np.log2(len(outputs)))) inputs = ( kwargs.pop("inputs") if "inputs" in kwargs else [(x + 1) for x in range(k)] ) state = kwargs.pop("state") if "state" in kwargs else False + # Replace 'None', '-', '#', or 'x' with '-'. + for i , output in enumerate(outputs): + if output in [None, '-', '#', 'x']: + outputs[i] = '-' # Placeholder value for missing data + print("Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.") + + # Generate extra lines in the table to account for missing lines + if len(outputs) < 2**k: + print(f"The total lines inputted are {len(outputs)}. Generating the missing rows for upto 2^{k} = {2**k} lines with placeholder value '-'.") + outputs.extend(['-'] * (2**k - len(outputs))) + return BooleanNode( id=id, name=name, diff --git a/cana/datasets/bio.py b/cana/datasets/bio.py index 180ad31..49ac706 100644 --- a/cana/datasets/bio.py +++ b/cana/datasets/bio.py @@ -21,6 +21,18 @@ _path = os.path.dirname(os.path.realpath(__file__)) """ Make sure we know what the current directory is """ +def TEMPY(): + """ + A temp txt file to test the loader. + + Returns: + (BooleanNetwork) + """ + return BooleanNetwork.from_file( + _path + "/tempy.txt", + name="Tempy", + keep_constants=True, + ) def THALIANA(): """Boolean network model of the control of flower morphogenesis in Arabidopsis thaliana diff --git a/cana/datasets/tempy.txt b/cana/datasets/tempy.txt new file mode 100644 index 0000000..63bfab8 --- /dev/null +++ b/cana/datasets/tempy.txt @@ -0,0 +1,59 @@ +# total number of nodes +.v 7 + +# labels of nodes and names of corresponding components +.l 1 One +.l 2 Two +.l 3 Three +.l 4 Four +.l 5 Five +.l 6 Six +.l 7 Seven + +# 1 = One +.n 1 0 +1 + +# 2 = Two +.n 2 0 +1 + +# 3 = Three +.n 3 0 +1 + +# 4 = Four +.n 4 0 +1 + +# 5 = Five +.n 5 0 +1 + +# 6 = Six +.n 6 2 1 2 +00 0 +01 1 +11 1 + +# 7 = Seven +.n 7 6 1 2 3 4 5 6 +0--000 0 +--0--- 0 +1--111 0 +-1---- 0 +-01-10 1 +-0110- 1 +001-1- 1 +-01-01 1 +-010-1 1 +101-0- 1 +101--0 1 +001--1 1 +001--1 1 +0011-- 1 +1010-- 1 +-011-0 1 +-0101- 1 + +.e end of file \ No newline at end of file diff --git a/cana/drawing/schema_vis.py b/cana/drawing/schema_vis.py index f9e3373..7d12de5 100644 --- a/cana/drawing/schema_vis.py +++ b/cana/drawing/schema_vis.py @@ -90,10 +90,7 @@ def plot_schemata(n, plotTS=True): x + cwidth / 2, y + cwidth / 10 * 4, text=text, - color=textcolor, - va="center", - ha="center", - fontsize=14, + color=textcolor,TODO family="serif", ) ) @@ -108,7 +105,7 @@ def plot_schemata(n, plotTS=True): xticks.append(x + cwidth / 2) x += cwidth + cxspace - x += sepcxspace + x += sepcxspaceTODO r = Rectangle( (x, y), width=cwidth, diff --git a/tutorials/Canalization - BioModels - Schematas.ipynb b/tutorials/Canalization - BioModels - Schematas.ipynb index 0f7aa9f..50f2015 100644 --- a/tutorials/Canalization - BioModels - Schematas.ipynb +++ b/tutorials/Canalization - BioModels - Schematas.ipynb @@ -224,10 +224,7 @@ " ax2.add_artist(Text(x+(cwidth/2),y+cwidth/10*4, text=out, color='white' if (out==1) else 'black', va='center', ha='center',fontsize=14,family='serif'))\n", " boxes.append(r)\n", " xticks.append(x+cwidth/2)\n", - " yticks.append(y+cwidth/2)\n", - " y += cwidth + cyspace\n", - " t += 1\n", - " y += sepcyspace\n", + " yticks.append(y+cwidth/2)TODO\n", "\n", " if len(boxes):\n", " ax2.add_collection(PatchCollection(boxes,match_original=True))\n", @@ -272,7 +269,7 @@ "outputs": [ { "data": { - "image/png": "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jNvKOjk5yRWSatzd3bFw4UIAzZvFHT58uM1yxgWgPDw8MH/+fHOFJytrq+v169cRHR2NI0eO4OrVq0hLS8Obb76pWjxERLZMtiSjKzNLbt++jeTkZADAs88+K1dIqlq0aJH0OsTGxuKXX34xOb927VpkZmYCANatW4f77rvP3CHKxprqeuDAAS7GRURkJrItK25syfD29kbfvn3vWP73v/89fvnlF1y7dg1HjhxBRUUFwsPDTfY+sWZarRYZGRmYOnUqDh8+DH9/f8ycOROenp7Izc3Fvn374OTkhA8++ADTp09XO9wusae6KmXevHno2bMnANPpvT4+PlJLEQBkZmbihx9+MHt8RESdIsrk/vvvFwGIzz333F2VHzRokAhA+jdu3DixvLxcrnDaZbyfXq9X/F6iKIq3b98WP/74Y3HcuHFi7969xe7du4u+vr5ifHy8WFxcrOi9L126ZNb6qllXvV5/V3W9du2a2KdPH5P33m9/+9s7XlPpf2fPnr2res6ePVvxWIiI5CKIYou1nlVw6dIlHDx4EG+++SYqKyvxxRdfYMKECYrdz7ictV6vt/n1EaqqqtCnTx8Atl/furo6aQDqnep6+PBhJCQkoKysDFOmTMHf/va3Nsu3vKY9UflPAhHZENWTDKOzZ88iKCgInp6eKC0tVWwAKJMM23QvSUZnrmlPLORPAhHZANl3Ye2sIUOGYPTo0fj5559RXFysdjhERETURRaTZADNAwgB4PLlyypHQkRERF1lMUlGfX09CgoKAABDhw5VORoiIiLqKrMmGXv37sXnn3+OpqYmk+NXrlzBnDlzUFlZicceewwPPPCAOcMiIiIiBci2TsbdOHXqFH7/+9+jT58+CAkJgZubGy5evIijR49Cr9dj4MCB2LJlizlDIiIiIoWYNcl47rnncPHiRezfvx9HjhxBdXU1XFxcMGzYMERHR+P111+Hu7u7OUMiIiIihZg1yXjwwQexYsUKc96SiIiIVGIxAz+JiIjItjDJICIiIkUwySAiIiJFMMkgIiIiRTDJICIiIkWYdXaJJamrq1M7BMW1rKOt19fW60dEZI3sNskw7k5qL+ytvkREpD676y4ZO3as2iGQgsaOHStttNdVWq3W7t4v9lZfIlKWIIqiqHYQREREZHvsriWDiIiIzINJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESni/wOA0OLezqw8BQAAAABJRU5ErkJggg==\n", + "image/png": "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jNvKOjk5yRWSatzd3bFw4UIAzZvFHT58uM1yxgWgPDw8MH/+fHOFJytrq+v169cRHR2NI0eO4OrVq0hLS8Obb76pWjxERLZMtiSjKzNLbt++jeTkZADAs88+K1dIqlq0aJH0OsTGxuKXX34xOb927VpkZmYCANatW4f77rvP3CHKxprqeuDAAS7GRURkJrItK25syfD29kbfvn3vWP73v/89fvnlF1y7dg1HjhxBRUUFwsPDTfY+sWZarRYZGRmYOnUqDh8+DH9/f8ycOROenp7Izc3Fvn374OTkhA8++ADTp09XO9wusae6KmXevHno2bMnANPpvT4+PlJLEQBkZmbihx9+MHt8RESdIsrk/vvvFwGIzz333F2VHzRokAhA+jdu3DixvLxcrnDaZbyfXq9X/F6iKIq3b98WP/74Y3HcuHFi7969xe7du4u+vr5ifHy8WFxcrOi9L126ZNb6qllXvV5/V3W9du2a2KdPH5P33m9/+9s7XlPpf2fPnr2res6ePVvxWIiI5CKIYou1nlVw6dIlHDx4EG+++SYqKyvxxRdfYMKECYrdz7ictV6vt/n1EaqqqtCnTx8Atl/furo6aQDqnep6+PBhJCQkoKysDFOmTMHf/va3Nsu3vKY9UflPAhHZENWTDKOzZ88iKCgInp6eKC0tVWwAKJMM23QvSUZnrmlPLORPAhHZANl3Ye2sIUOGYPTo0fj5559RXFysdjhERETURRaTZADNAwgB4PLlyypHQkRERF1lMUlGfX09CgoKAABDhw5VORoiIiLqKrMmGXv37sXnn3+OpqYmk+NXrlzBnDlzUFlZicceewwPPPCAOcMiIiIiBci2TsbdOHXqFH7/+9+jT58+CAkJgZubGy5evIijR49Cr9dj4MCB2LJlizlDIiIiIoWYNcl47rnncPHiRezfvx9HjhxBdXU1XFxcMGzYMERHR+P111+Hu7u7OUMiIiIihZg1yXjwwQexYsUKc96SiIiIVGIxAz+JiIjItjDJICIiIkUwySAiIiJFMMkgIiIiRTDJICIiIkWYdXaJJamrq1M7BMW1rKOt19fW60dEZI3sNskw7k5qL+ytvkREpD676y4ZO3as2iGQgsaOHStttNdVWq3W7t4v9lZfIlKWIIqiqHYQREREZHvsriWDiIiIzINJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESmCSQYREREpgkkGERERKYJJBhERESni/wOA0OLezqw8BQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] From 03b532ad24d538ed2a4d3cc3e55d119251dea5fe Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Wed, 5 Jun 2024 12:30:59 -0400 Subject: [PATCH 04/14] adding temp to branch --- cana/drawing/schema_vis.py | 7 +- tutorials/temp.ipynb | 297 +++++++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 tutorials/temp.ipynb diff --git a/cana/drawing/schema_vis.py b/cana/drawing/schema_vis.py index 7d12de5..f9e3373 100644 --- a/cana/drawing/schema_vis.py +++ b/cana/drawing/schema_vis.py @@ -90,7 +90,10 @@ def plot_schemata(n, plotTS=True): x + cwidth / 2, y + cwidth / 10 * 4, text=text, - color=textcolor,TODO + color=textcolor, + va="center", + ha="center", + fontsize=14, family="serif", ) ) @@ -105,7 +108,7 @@ def plot_schemata(n, plotTS=True): xticks.append(x + cwidth / 2) x += cwidth + cxspace - x += sepcxspaceTODO + x += sepcxspace r = Rectangle( (x, y), width=cwidth, diff --git a/tutorials/temp.ipynb b/tutorials/temp.ipynb new file mode 100644 index 0000000..9b76269 --- /dev/null +++ b/tutorials/temp.ipynb @@ -0,0 +1,297 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax. Perhaps you forgot a comma? (schema_vis.py, line 93)", + "output_type": "error", + "traceback": [ + "Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n", + "\u001b[0m File \u001b[1;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3577\u001b[0m in \u001b[1;35mrun_code\u001b[0m\n exec(code_obj, self.user_global_ns, self.user_ns)\u001b[0m\n", + "\u001b[0;36m Cell \u001b[0;32mIn[2], line 11\u001b[0;36m\n\u001b[0;31m from cana.drawing.schema_vis import plot_schemata\u001b[0;36m\n", + "\u001b[0;36m File \u001b[0;32m/data/siyer/CANA/cana/drawing/schema_vis.py:93\u001b[0;36m\u001b[0m\n\u001b[0;31m color=textcolor,TODO\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax. Perhaps you forgot a comma?\n" + ] + } + ], + "source": [ + "from cana.datasets.bio import TEMPY\n", + "from cana.datasets.bio import (\n", + " THALIANA,\n", + " DROSOPHILA,\n", + " BUDDING_YEAST,\n", + " MARQUESPITA,\n", + " LEUKEMIA,\n", + " BREAST_CANCER,\n", + ")\n", + "from cana.boolean_node import BooleanNode\n", + "from cana.drawing.schema_vis import plot_schemata\n", + "from cana.drawing.plot_look_up_table import plot_look_up_table\n", + "from cana.utils import fill_out_lut" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# modified the BooleanNetwork.from_string_cnet function that is called in the BooleanNetwork.from_file function to check for duplicate values in the inputs and outputs of the nodes.\n", + "# this will print a warning message if there are duplicate values in the inputs and outputs of the nodes.\n", + "# This also generates a lookup table data for nodes with k>1\n", + "\n", + "# plot_schemata(tempy.nodes[4])\n", + "# plot_look_up_table(tempy.nodes[4])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "thaliana = THALIANA()\n", + "drosophila = DROSOPHILA()\n", + "budding_yeast = BUDDING_YEAST()\n", + "marquespita = MARQUESPITA()\n", + "leukemia = LEUKEMIA()\n", + "breast_cancer = BREAST_CANCER()\n", + "tempy = TEMPY()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# print(thaliana.nodes[0].outputs)\n", + "node = tempy.nodes[4]\n", + "plot_look_up_table(node)\n", + "plot_schemata(node)\n", + "print(node.schemata_look_up_table(type=\"pi\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "generating permutations of output lists for incomplete data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# need to modify the output list from data function to include the this following function\n", + "def from_output_list_with_missing_data(outputs=list(), *args, **kwargs):\n", + " \"\"\"\n", + " Instanciate a Boolean Node from a output transition list.\n", + "\n", + " For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing.\n", + "\n", + " Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs.\n", + "\n", + " Args:\n", + " outputs (list) : The transition outputs of the node.\n", + "\n", + " Returns:\n", + " (BooleanNode) : the instanciated object.\n", + "\n", + " Example:\n", + " >>> BooleanNode.from_output_list_with_missing_data(outputs=[0,0,0,'-',1], name=\"AND\")\n", + " \"\"\"\n", + " id = kwargs.pop(\"id\") if \"id\" in kwargs else 0\n", + " name = kwargs.pop(\"name\") if \"name\" in kwargs else \"x\"\n", + " k = int(np.ceil(np.log2(len(outputs))))\n", + " inputs = kwargs.pop(\"inputs\") if \"inputs\" in kwargs else [(x + 1) for x in range(k)]\n", + " state = kwargs.pop(\"state\") if \"state\" in kwargs else False\n", + "\n", + " # Replace 'None', '-', '#', or 'x' with '-'.\n", + " for i in range(len(outputs)):\n", + " if outputs[i] in [None, \"-\", \"#\", \"x\"]:\n", + " outputs[i] = \"-\" # Placeholder value for missing data\n", + " print(\n", + " \"Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.\"\n", + " )\n", + "\n", + " # Generate extra lines in the table to account for missing lines\n", + " if len(outputs) < 2**k:\n", + " print(\n", + " f\"Some of the lines in the data are missing and have been replaced with the placeholder value '-' for upto 2^k lines. i.e. the total lines inputted are {len(outputs)}, then the function will generate the missing rows for upto 2^{k} = {2**k} lines.\"\n", + " )\n", + " outputs.extend([\"-\"] * (2**k - len(outputs)))\n", + "\n", + " return BooleanNode(\n", + " id=id,\n", + " name=name,\n", + " k=k,\n", + " inputs=inputs,\n", + " state=state,\n", + " outputs=outputs,\n", + " *args,\n", + " **kwargs,\n", + " )\n", + "\n", + "\n", + "# def generate_output_list_permutations(incomplete_boolean_node):\n", + "# # generating all possible output_list permutations for the incomplete boolean node.\n", + "\n", + "# outputs = incomplete_boolean_node.outputs\n", + "# print(outputs)\n", + "# missing_data_indices = [i for i, x in enumerate(outputs) if x == '-']\n", + "# # output_list_permutations = [outputs.copy() for _ in range(2 ** len(missing_data_indices))]\n", + "\n", + "# #generating binarytable for size: no. of missing values\n", + "# table=[]\n", + "# output_list_permutations=[]\n", + "# for i in range(2 ** len(missing_data_indices)):\n", + "# row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))]\n", + "# table.append(row)\n", + "# output_list_permutations.append(outputs.copy())\n", + "# for j in range(len(missing_data_indices)):\n", + "# output_list_permutations[i][missing_data_indices[j]] = table[i][j]\n", + "# return output_list_permutations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "incomplete_output = [0, 0, None, 1, 1, 0]\n", + "# incomplete_output = tempy.nodes[5].outputs.copy()\n", + "incomplete_output\n", + "\n", + "\n", + "# creating a boolean node for incomplete data\n", + "incomplete_boolean_node = from_output_list_with_missing_data(incomplete_output)\n", + "print(incomplete_boolean_node)\n", + "# output_list_permutations = generate_output_list_permutations(incomplete_boolean_node)\n", + "# print(f'Following are the pemutations of the incomplete output list of length:{len(output_list_permutations)}')\n", + "# output_list_permutations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "incomplete_boolean_node.look_up_table()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Added missing data code to the from_output_list funciton in boolean_node.py. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # testing modified from_output_list function\n", + "# incomplete_output = [0,0, None, 1,1,0]\n", + "# incomplete_boolean_node = BooleanNode.from_output_list(incomplete_output)\n", + "# print(incomplete_boolean_node.outputs)\n", + "# incomplete_boolean_node.look_up_table()\n", + "AND = BooleanNode.from_output_list([0, 1, 0, 1])\n", + "print(AND.schemata_look_up_table(type=\"pi\"))\n", + "plot_look_up_table(AND)\n", + "print(AND.look_up_table())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# # partial_lut = [('1--','1'),('101','0'),('011','0'),('01-','1')]\n", + "# # partial_lut = [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')]\n", + "partial_lut = [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"0\")]\n", + "generated_lut = fill_out_lut(partial_lut)\n", + "generated_lut" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# write a function that converts datya in the example form 00-- 0\\n1--1 1\\n11-- 0 to this example form: ('00--','0'),('1--1','1'),('11--','0')\n", + "def from_example_form_to_list(example_form):\n", + " example_form = example_form.split(\"\\n\")\n", + " example_form = [tuple(x.split(\" \")) for x in example_form]\n", + " return example_form\n", + "\n", + "\n", + "print(from_example_form_to_list(\"###1 0\\n#1## 0\\n1### 0\\n##1# 0\\n0000 1\"))\n", + "\n", + "\n", + "# write a function that converts data in the example form ('00--','0'),('1--1','1'),('11--','0') to this example form: 00-- 0\\n1--1 1\\n11-- 0\n", + "def from_list_to_example_form(example_form):\n", + " example_form = [x[0] + \" \" + x[1] for x in example_form]\n", + " example_form = \"\\n\".join(example_form)\n", + " return example_form\n", + "\n", + "\n", + "# print(from_list_to_example_form(partial_lut))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "SoftComputing", + "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": 2 +} From 7eb27b8e7b0c7cab0801a7c69290caeff2b6b1f9 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Fri, 14 Jun 2024 17:18:50 -0400 Subject: [PATCH 05/14] feat: Added partial_LUT demo tutorial, BooleanNode instantiation with partial LUT using fill_out_lut() and from_output_list() --- cana/boolean_network.py | 24 +- cana/boolean_node.py | 26 +- cana/datasets/bio.py | 13 + cana/datasets/partial_LUT_demo_nodes.txt | 62 ++ cana/datasets/tempy.txt | 7 +- cana/drawing/plot_look_up_table.py | 5 +- cana/random_boolean_network.py | 65 +- cana/utils.py | 22 +- ...lization - BioModels - Look Up Table.ipynb | 226 +++++++ tests/test_boolean_node.py | 2 +- tutorials/Generating from Partial LUTs.ipynb | 405 ++++++++++++ tutorials/temp.ipynb | 606 +++++++++++++++--- 12 files changed, 1363 insertions(+), 100 deletions(-) create mode 100644 cana/datasets/partial_LUT_demo_nodes.txt create mode 100644 docs/Canalization - BioModels - Look Up Table.ipynb create mode 100644 tutorials/Generating from Partial LUTs.ipynb diff --git a/cana/boolean_network.py b/cana/boolean_network.py index ad9d0db..2e0d5f0 100644 --- a/cana/boolean_network.py +++ b/cana/boolean_network.py @@ -69,9 +69,10 @@ def __init__( keep_constants=False, bin2num=None, num2bin=None, - verbose=False, + verbose=False, # Verbose mode for debugging purposes *args, **kwargs + # TODO: [SRI] ask Jordan if we should add a requirement called complete = True or False so as to generate patial look up tables based on the completeness of the network ): # NOTE: *args and **kwargs don't do anything. I'm not sure why they wre added here, so I'm not going to remove them. @@ -175,6 +176,7 @@ def from_file(self, file, type="cnet", keep_constants=True, **kwargs): def from_string_cnet(self, string, keep_constants=True, **kwargs): """ Instanciates a Boolean Network from a string in cnet format. + The cnet format is similar to the Berkeley Logic Interchange Format (BLIF). Args: string (string): A cnet format representation of a Boolean Network. @@ -250,7 +252,7 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = '!' logic_line = network_file.readline().strip() - + # TODO: [SRI] check if I need to add a Prime Implicant condition in the function ## to generate with Prime Implicants(PI) # logic[inode]["out"] = [ # '0' for i in range(2**indegree) if indegree > 0 @@ -361,7 +363,7 @@ def from_string_boolean(self, string, keep_constants=True, **kwargs): @classmethod def from_dict(self, logic, keep_constants=True, **kwargs): - """Instanciaets a BooleanNetwork from a logic dictionary. + """Instanciates a BooleanNetwork from a logic dictionary. Args: logic (dict) : The logic dict. @@ -372,6 +374,20 @@ def from_dict(self, logic, keep_constants=True, **kwargs): See also: :func:`from_file` :func:`from_dict` + + Examples: + Logic should be structured as follow: + + .. code-block:: python + + logic = { + 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]}, + 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]}, + 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]} + } + + # Instanciate the BooleanNetwork + bn = BooleanNetwork.from_dict(logic) """ Nnodes = len(logic) constants = {} @@ -891,7 +907,7 @@ def trajectory_to_attractor( return trajectory def attractor(self, initial): - """Computes the trajectory starting at ``initial`` until it reaches an attracor (this is garanteed) + """Computes the trajectory starting at ``initial`` until it reaches an attractor (this is guaranteed) Args: initial (string): the initial state. diff --git a/cana/boolean_node.py b/cana/boolean_node.py index 80d2ab6..f80a2f9 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -29,7 +29,7 @@ outputs_to_binstates_of_given_type, statenum_to_binstate, ) -from cana.utils import input_monotone, ncr +from cana.utils import input_monotone, ncr, fill_out_lut class BooleanNode(object): @@ -155,6 +155,30 @@ def from_output_list(self, outputs=list(), *args, **kwargs): *args, **kwargs ) + + def from_partial_lut(partial_lut, *args, **kwargs): + """ + Instanciate a Boolean Node from a partial look-up table. + + Uses the fill_out_lut function to complete the look-up table. Extracts the output list from the completed look-up table. Then instanciates the Boolean Node from the output list using the from_output_list method. + + Args: + partial_lut (list) : A partial look-up table of the node. + + Returns: + (BooleanNode) : the instanciated object. + + Example: + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], name="EG") + + """ + + generated_lut = fill_out_lut(partial_lut) + output_list = [x[1] for x in generated_lut] + + return BooleanNode.from_output_list(output_list, *args, **kwargs) + + def set_constant(self, constant=True, state=None): """Sets whether the node is to be treated as a contant diff --git a/cana/datasets/bio.py b/cana/datasets/bio.py index 49ac706..f7c1863 100644 --- a/cana/datasets/bio.py +++ b/cana/datasets/bio.py @@ -34,6 +34,19 @@ def TEMPY(): keep_constants=True, ) +def PARTIAL_LUTS_DEMO(): + """ + A txt file with different types of Partial LUTs to demo the Partial Lut generation function. + + Returns: + (BooleanNetwork) + """ + return BooleanNetwork.from_file( + _path + "/partial_LUT_demo_nodes.txt", + name="Partial LUTs Demo", + keep_constants=True, + ) + def THALIANA(): """Boolean network model of the control of flower morphogenesis in Arabidopsis thaliana diff --git a/cana/datasets/partial_LUT_demo_nodes.txt b/cana/datasets/partial_LUT_demo_nodes.txt new file mode 100644 index 0000000..0c80d0f --- /dev/null +++ b/cana/datasets/partial_LUT_demo_nodes.txt @@ -0,0 +1,62 @@ +# total number of nodes +.v 7 + +# labels of nodes and names of corresponding components +.l 1 One +.l 2 Two +.l 3 Three +.l 4 Four +.l 5 Five +.l 6 Six +.l 7 Seven + +# 1 = One +.n 1 0 +1 + +# 2 = Two +.n 2 0 +1 + +# 3 = Three +.n 3 0 +1 + +# 4 = Four +.n 4 0 +1 + +# 5 = Five +.n 5 3 3 4 2 +000 1 +0-0 0 +1-0 1 +111 1 + +# 6 = Six +.n 6 2 1 2 +00 0 +01 1 +11 1 + +# 7 = Seven +.n 7 6 1 2 3 4 5 6 +0--000 0 +--0--- 0 +1--111 0 +-1---- 0 +-01-10 1 +-0110- 1 +001-1- 1 +-01-01 1 +-010-1 1 +101-0- 1 +101--0 1 +001--1 1 +001--1 1 +0011-- 1 +1010-- 1 +-011-0 1 +-0101- 1 + +.e end of file \ No newline at end of file diff --git a/cana/datasets/tempy.txt b/cana/datasets/tempy.txt index 63bfab8..0c80d0f 100644 --- a/cana/datasets/tempy.txt +++ b/cana/datasets/tempy.txt @@ -27,8 +27,11 @@ 1 # 5 = Five -.n 5 0 -1 +.n 5 3 3 4 2 +000 1 +0-0 0 +1-0 1 +111 1 # 6 = Six .n 6 2 1 2 diff --git a/cana/drawing/plot_look_up_table.py b/cana/drawing/plot_look_up_table.py index 1fd08dc..3982700 100644 --- a/cana/drawing/plot_look_up_table.py +++ b/cana/drawing/plot_look_up_table.py @@ -18,7 +18,10 @@ def plot_look_up_table(n): ------- None """ - + # Check if n.inputs has any values + if not n.inputs: + return print('No inputs to plot') + # Init values from BooleanNode k = n.k if n.k>=1 else 1 inputs = n.inputs if not n.constant else [n.name] diff --git a/cana/random_boolean_network.py b/cana/random_boolean_network.py index a96dd14..870fadb 100644 --- a/cana/random_boolean_network.py +++ b/cana/random_boolean_network.py @@ -34,7 +34,25 @@ def regular_boolean_network( niter_remove=1000, ): """ - TODO: description + Generate a random regular boolean network. + + Args: + N (int) : Number of nodes in the network. + K (int) : Degree of each node in the network. + bias (float) : Bias for the output transitions. + bias_constraint (str) : Constraint for the bias. Options are 'soft', 'hard', 'soft_no_constant'. + keep_constants (bool) : Keep constant nodes. + remove_multiedges (bool) : Remove multi-edges. + niter_remove (int) : Number of iterations to try to remove duplicate edges. + + Returns: + (BooleanNetwork) : The boolean network object. + + Examples: + A regular boolean network with 10 nodes, each with 2 inputs and a bias of 0.5. + + >>> bn = regular_boolean_network(N=10, K=2, bias=0.5) + """ din = [K] * N # in-degree distrubtion dout = [K] * N # out-degree distrubtion @@ -72,7 +90,24 @@ def er_boolean_network( niter_remove=1000, ): """ - TODO: description + Generate a random Erdos-Renyi boolean network. + + Args: + N (int) : Number of nodes in the network. + p (float) : Probability for edge creation. + bias (float) : Bias for the output transitions. + bias_constraint (str) : Constraint for the bias. Options are 'soft', 'hard', 'soft_no_constant'. + remove_multiedges (bool) : Remove multi-edges. + niter_remove (int) : Number of iterations to try to remove duplicate edges. + + Returns: + (BooleanNetwork) : The boolean network object. + + Examples: + A random Erdos-Renyi boolean network with 10 nodes and a probability of 0.2. + + >>> bn = er_boolean_network(N=10, p=0.2) + """ er_graph = nx.erdos_renyi_graph(N, p, directed=True) @@ -98,7 +133,21 @@ def er_boolean_network( def random_automata_table(indegree, bias, bias_constraint="soft"): """ - TODO: description + Generate a random automata table. + + Args: + indegree (int) : Number of inputs. + bias (float) : Bias for the output transitions. + bias_constraint (str) : Constraint for the bias. Options are 'soft', 'hard', 'soft_no_constant'. + + Returns: + (list) : A list of output transitions. + + Examples: + A random automata table with 2 inputs and a bias of 0.5. + + >>> random_automata_table(indegree=2, bias=0.5) + """ if bias_constraint == "soft": return [int(random.random() < bias) for b in range(2**indegree)] @@ -119,7 +168,15 @@ def random_automata_table(indegree, bias, bias_constraint="soft"): def _remove_duplicate_edges(graph, niter_remove=100): """ - TODO: description + Remove duplicate edges from a graph. + + Args: + graph (nx.DiGraph) : A directed graph. + niter_remove (int) : Number of iterations to try to remove duplicate edges. + + Returns: + (nx.DiGraph) : A directed graph without duplicate edges. + """ edge_list = list(graph.edges()) edge_frequency = Counter(edge_list) diff --git a/cana/utils.py b/cana/utils.py index e6e54f2..8d31334 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -341,22 +341,33 @@ def fill_out_lut(partial_lut): Example: >>> fill_out_lut([('00', 0), ('01', 0), ('1-', 1), ('11', 1)]) [('00', 0), ('01', 0), ('10', 1), ('11', 1)] + + # TODO: [SRI] update function to handle txt file input style to generate the partial LUT + # TODO: [SRI] fill up '?' symbols based on specified criteria- a coin toss, or specified bias + # TODO: [SRI] add bias criteria to handle incomplete output values + # TODO: [SRI] generate LUT with a specified effective connectivity + # TODO: [SRI] generate LUT from two symbol schemata, with a specified ratio of wildcard symbols + # TODO: [SRI] add tests for canonical rule logic, rule 90, rule 110 + # TODO: [SRI] use examples COSA rule, GKL rule where you fill up LUT based on the annihilation inputs and see if it matches with the rules plus bias. """ + # Check if all the input entries of the partial LUT are of the same length. if len(set([len(x[0]) for x in partial_lut])) != 1: raise ValueError('All the input entries of the partial LUT must be of the same length.') k = len(partial_lut[0][0]) all_states = {entry[0]: entry[1] for entry in partial_lut} + for entry in partial_lut: if not all([x in ['0','1','-','#','2','x'] for x in entry[0]]): raise ValueError('All the input entries of the partial LUT must be valid binary strings.') - elif any([x in ['-', '#','2','x'] for x in entry[0]]): + elif any([x in ['-', '#','2','x'] for x in entry[0]]): missing_data_indices = [i for i, x in enumerate(entry[0]) if x == '-'] table=[] output_list_permutations=[] + for i in range(2 ** len(missing_data_indices)): row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))] table.append(row) @@ -364,6 +375,7 @@ def fill_out_lut(partial_lut): for j in range(len(missing_data_indices)): output_list_permutations[i] = output_list_permutations[i][:missing_data_indices[j]] + str(table[i][j]) + output_list_permutations[i][missing_data_indices[j]+1:] del all_states[entry[0]] + for perm in output_list_permutations: if perm in all_states and all_states[perm] != entry[1]: # print('Clashing output values for entry:', perm) @@ -374,7 +386,13 @@ def fill_out_lut(partial_lut): for i in range(2**k): state = bin(i)[2:].zfill(k) if state not in all_states: - all_states[state] = '?' + all_states[state] = '?' # TODO: [SRI] Add option to generate 0 or 1 with 0.5 probability + # Print a statement if there are any missing values '?' in the LUT. Else print a statement that the LUT is complete. + if '?' in all_states.values(): + print('The LUT is incomplete. Missing values are represented by \'?\'') + else: + print('The LUT is complete.') + all_states = sorted(all_states.items(), key=lambda x: x[0]) return all_states \ No newline at end of file diff --git a/docs/Canalization - BioModels - Look Up Table.ipynb b/docs/Canalization - BioModels - Look Up Table.ipynb new file mode 100644 index 0000000..7c76fbe --- /dev/null +++ b/docs/Canalization - BioModels - Look Up Table.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Tutorial - Plotting Look Up Table (LUT)\n", + "This tutorial shows how to plot Prime Implicants (F') and Two-Symbol (F'') schematas" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from matplotlib.text import Text\n", + "from matplotlib.patches import Circle, Rectangle, RegularPolygon\n", + "from matplotlib.collections import PatchCollection" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from cana.datasets.bio import THALIANA #, DROSOPHILA, BUDDING_YEAST" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "N = THALIANA()\n", + "#N = DROSOPHILA()\n", + "#N = BUDDING_YEAST()\n", + "print(N)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "def plot_look_up_table(n):\n", + " # Init values from BooleanNode\n", + " k = n.k if n.k>=1 else 1\n", + " inputs = n.inputs if not n.constant else [n.name]\n", + " inputlabels = [n.network.get_node_name(i)[0] if n.network is not None else i for i in inputs]\n", + " LUT = n.look_up_table().sort_index(ascending=False)\n", + " # Count number of F in the LUT\n", + " n_fs = LUT.shape[0]\n", + " # Schemata Cell Width and spacing\n", + " cwidth = 60.\n", + " cxspace = 0\n", + " cyspace = 6\n", + " border = 1\n", + " sepcxspace = 21\n", + " sepcyspace = 15\n", + " dpi = 150.\n", + " # Margins\n", + " top, right, bottom, left, hs = 120, 25, 25, 60, 25\n", + " # Axes Width & Height\n", + " ax1width = ((k*(cwidth+cxspace))+sepcxspace+(cwidth))\n", + " ax1height = (n_fs*(cwidth+cyspace)-cyspace)\n", + " # Figure Width & Height\n", + " fwidth = (left + ax1width + hs + right)\n", + " fheight = (bottom + ax1height + top)\n", + " # Percentages for Axes location\n", + " _ax1w = ((ax1width*100) / fwidth) / 100\n", + " _ax1h = ((ax1height*100) / fheight) / 100\n", + " _bottom = ((bottom*100) / fheight) / 100\n", + " _left = ((left*100) / fwidth) / 100\n", + " _hs = ((hs*100) / fwidth) / 100\n", + " # Init Figure\n", + " fig = plt.figure(figsize=(fwidth/dpi,fheight/dpi), facecolor='w', dpi=dpi)\n", + " ax1 = fig.add_axes((_left,_bottom,_ax1w,_ax1h), aspect=1, label='LUT')\n", + "\n", + " ### LUT Plot ###\n", + "\n", + " yticks = []\n", + " patches = []\n", + " x,y = 0.,0.\n", + " #\n", + " for i,r in LUT.iterrows():\n", + " ins = str(r['In:'])\n", + " out = r['Out:']\n", + " x = 0.\n", + " xticks = []\n", + " for input in ins:\n", + " if input == '0':\n", + " facecolor = 'white'\n", + " textcolor = 'black'\n", + " elif input == '1':\n", + " facecolor = 'black'\n", + " textcolor = 'white' \n", + " text = '{label:s}'.format(label=input)\n", + " ax1.add_artist(Text(x+cwidth/2,y+cwidth/10*4, text=text, color=textcolor, va='center', ha='center',fontsize=14,family='serif'))\n", + " r = Rectangle((x,y), width=cwidth, height=cwidth, facecolor=facecolor, edgecolor='black')\n", + " patches.append(r)\n", + " xticks.append(x+cwidth/2)\n", + " x += cwidth + cxspace\n", + "\n", + " x += sepcxspace\n", + " r = Rectangle((x,y), width=cwidth, height=cwidth, facecolor='black' if (out==1) else 'white', edgecolor='black')\n", + " ax1.add_artist(Text(x-(sepcxspace/2)-(cxspace/2),y+cwidth/10*4, text=':', color='black', va='center', ha='center',fontsize=14,weight='bold',family='serif'))\n", + " ax1.add_artist(Text(x+(cwidth/2),y+cwidth/10*4, text=out, color='white' if (out==1) else 'black', va='center', ha='center',fontsize=14,family='serif'))\n", + " patches.append(r)\n", + " xticks.append(x+cwidth/2)\n", + " yticks.append(y+cwidth/2)\n", + " y += cwidth + cyspace\n", + "\n", + " #y += sepcyspace\n", + "\n", + " ax1.add_collection(PatchCollection(patches, match_original=True))\n", + " #\n", + " ax1.set_yticks(yticks)\n", + " ax1.set_yticklabels([r\"$f_{%d}$\"%(i+1) for i in range(n_fs)[::-1]], fontsize=14)\n", + " ax1.set_xticks(xticks)\n", + " ax1.set_xticklabels(inputlabels + ['%s'%(n.name)], rotation=90, fontsize=14)\n", + " #\n", + " ax1.xaxis.tick_top()\n", + " # Remove Tick\n", + " ax1.tick_params(which='major',pad=7)\n", + " for tic in ax1.xaxis.get_major_ticks():\n", + " tic.tick1On = tic.tick2On = False\n", + " for tic in ax1.yaxis.get_major_ticks():\n", + " tic.tick1On = tic.tick2On = False\n", + " # Remove Border\n", + " ax1.spines['top'].set_visible(False)\n", + " ax1.spines['right'].set_visible(False)\n", + " ax1.spines['bottom'].set_visible(False)\n", + " ax1.spines['left'].set_visible(False)\n", + " # Limits\n", + " ax1.set_xlim(-border,ax1width+border)\n", + " ax1.set_ylim(-border,ax1height+border)\n", + " #ax1.invert_yaxis() \n", + "\n", + " # FileName\n", + " filename = n.name\n", + " filename = filename.replace('/','_')\n", + " filename = filename.replace(',','_')\n", + " \n", + " ## Display\n", + " display(fig)\n", + " \n", + " plt.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "node = N.nodes[2]\n", + "plot_look_up_table(node)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index b6a3aad..93cd994 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -475,7 +475,7 @@ def test_partial_lut(): [('00','1'),('01','1')], [('0-','1'),('10','1')], [('001','1'),('01-','1'),('1-1','0')], - [('00--', '0'), ('1--1','1'), ('11--','0')] + [('00--', '0'), ('1--1','1'), ('11--','0')], # Checking for Contradictory values. Should be marked with '!'. ] expected_filled = [ [('00','1'),('01','1'),('10','?'),('11','?')], diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb new file mode 100644 index 0000000..6a91bff --- /dev/null +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -0,0 +1,405 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Demo for generating complete LUTs from partial input\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "from cana.datasets.bio import PARTIAL_LUTS_DEMO\n", + "from cana.drawing.schema_vis import plot_schemata\n", + "from cana.drawing.plot_look_up_table import plot_look_up_table\n", + "from cana.utils import fill_out_lut\n", + "\n", + "from cana.boolean_node import BooleanNode\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Partial LUTs\n", + "\n", + "These are incomplete effective graphs with '-' signifying the wildcard symbol. Visually inspecting an effective graph doesn't allow us to infer its status of completeness or identify any inherent contradictions within the inputs.\n", + "\n", + "The fill_out_lut() function enables us to check for contradictory output data. The contradictory outputs are marked by '!'\n", + "\n", + "The fill_out_lut() function also checks for missing rules in the LUT, allowing us to correct out data infered from sources and explore state spaces yet to be understood. These outputs are marked by '?'." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('000', '?'),\n", + " ('001', '?'),\n", + " ('010', '1'),\n", + " ('011', '!'),\n", + " ('100', '1'),\n", + " ('101', '!'),\n", + " ('110', '1'),\n", + " ('111', '1')]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Using the fill_out_lut function found in utils.py\n", + "\n", + "partial_luts = [\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [('1--','1'),('101','0'),('011','0'),('01-','1')],\n", + " [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')],\n", + "]\n", + "generated_lut = fill_out_lut(partial_luts[1])\n", + "generated_lut" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Partial LUTs in BNS format\n", + "\n", + "BNS is a software tool for computing attractors in Boolean Networks with Synchronous update. Synchronous Boolean networks are used for the modeling of genetic regulatory networks.\n", + "\n", + "BNS reads in a Boolean network description represented in a .cnet format similar to the Berkeley Logic Interchange Format (BLIF) format commonly used in synthesis and verification tools and prints out the set of network's attractors.\n", + "\n", + "Check: " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entry clash in node 5 for {'000'} i.e. State number: 0\n", + "\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "partial_luts = PARTIAL_LUTS_DEMO() # Instantiating a sample partial_luts dataset from the dataset folder.\n", + "\n", + "node = partial_luts.nodes[5]\n", + "\n", + "print(node)\n", + "# print(node.look_up_table())\n", + "# print(node.schemata_look_up_table())\n", + "\n", + "plot_look_up_table(node)\n", + "plot_schemata(node)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "# plot_schemata(node)\n", + "# plot_look_up_table(node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiating a BooleanNode object using partial LUT\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['?', '?', '1', '!', '1', '!', '1', '1']\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
In:Out:
0000?
1001?
20101
3011!
41001
5101!
61101
71111
\n", + "
" + ], + "text/plain": [ + " In: Out:\n", + "0 000 ?\n", + "1 001 ?\n", + "2 010 1\n", + "3 011 !\n", + "4 100 1\n", + "5 101 !\n", + "6 110 1\n", + "7 111 1" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "\n", + "partial_luts = [\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [('1--','1'),('101','0'),('011','0'),('01-','1')],\n", + " [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')],\n", + "]\n", + "partial_lut = partial_luts[1]\n", + "\n", + "\n", + "generated_lut = fill_out_lut(partial_lut) # Using the fill_out_lut function found in utils.py\n", + "output_list = [x[1] for x in generated_lut] # Extracting the output values from the generated_lut\n", + "print(output_list)\n", + "generated_node = BooleanNode.from_output_list(output_list) # Instantiating a BooleanNode object from the output_list\n", + "generated_node.look_up_table() # Displaying the look-up table of the generated_node" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
In:Out:
0000?
1001?
20101
3011!
41001
5101!
61101
71111
\n", + "
" + ], + "text/plain": [ + " In: Out:\n", + "0 000 ?\n", + "1 001 ?\n", + "2 010 1\n", + "3 011 !\n", + "4 100 1\n", + "5 101 !\n", + "6 110 1\n", + "7 111 1" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Combining the above functions into a single function under BooleanNode class\n", + "\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut) \n", + "print(generated_node)\n", + "generated_node.look_up_table()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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": 2 +} diff --git a/tutorials/temp.ipynb b/tutorials/temp.ipynb index 9b76269..4ccbd38 100644 --- a/tutorials/temp.ipynb +++ b/tutorials/temp.ipynb @@ -6,26 +6,19 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np" + "import numpy as np\n", + "from matplotlib.text import Text\n", + "from matplotlib import pyplot as plt\n", + "from matplotlib.collections import PatchCollection\n", + "from matplotlib.patches import Rectangle\n", + "from IPython.display import display" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax. Perhaps you forgot a comma? (schema_vis.py, line 93)", - "output_type": "error", - "traceback": [ - "Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n", - "\u001b[0m File \u001b[1;32m/data/siyer/CANA/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3577\u001b[0m in \u001b[1;35mrun_code\u001b[0m\n exec(code_obj, self.user_global_ns, self.user_ns)\u001b[0m\n", - "\u001b[0;36m Cell \u001b[0;32mIn[2], line 11\u001b[0;36m\n\u001b[0;31m from cana.drawing.schema_vis import plot_schemata\u001b[0;36m\n", - "\u001b[0;36m File \u001b[0;32m/data/siyer/CANA/cana/drawing/schema_vis.py:93\u001b[0;36m\u001b[0m\n\u001b[0;31m color=textcolor,TODO\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax. Perhaps you forgot a comma?\n" - ] - } - ], + "outputs": [], "source": [ "from cana.datasets.bio import TEMPY\n", "from cana.datasets.bio import (\n", @@ -39,12 +32,15 @@ "from cana.boolean_node import BooleanNode\n", "from cana.drawing.schema_vis import plot_schemata\n", "from cana.drawing.plot_look_up_table import plot_look_up_table\n", - "from cana.utils import fill_out_lut" + "from cana.utils import fill_out_lut\n", + "\n", + "from cana.boolean_node import BooleanNode\n", + "from cana.boolean_network import BooleanNetwork" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -58,9 +54,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entry clash in node 5 for {'000'} i.e. State number: 0\n" + ] + } + ], "source": [ "thaliana = THALIANA()\n", "drosophila = DROSOPHILA()\n", @@ -73,15 +77,85 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ - "# print(thaliana.nodes[0].outputs)\n", - "node = tempy.nodes[4]\n", - "plot_look_up_table(node)\n", - "plot_schemata(node)\n", - "print(node.schemata_look_up_table(type=\"pi\"))" + "# plot_schemata(node)\n", + "# print(node.schemata_look_up_table(type=\"pi\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " In: Out:\n", + "0 000000 0\n", + "1 000001 0\n", + "2 000010 0\n", + "3 000011 0\n", + "4 000100 0\n", + ".. ... ...\n", + "59 111011 0\n", + "60 111100 0\n", + "61 111101 0\n", + "62 111110 0\n", + "63 111111 0\n", + "\n", + "[64 rows x 2 columns]\n", + " Input Output\n", + "0 ##0### 0\n", + "1 #1#### 0\n", + "2 0##000 0\n", + "3 1##111 0\n", + "4 001##1 1\n", + "5 101#0# 1\n", + "6 #011#0 1\n", + "7 0011## 1\n", + "8 #01#01 1\n", + "9 #0110# 1\n", + "10 #0101# 1\n", + "11 #010#1 1\n", + "12 001#1# 1\n", + "13 #01#10 1\n", + "14 1010## 1\n", + "15 101##0 1\n", + "\n" + ] + } + ], + "source": [ + "\n", + "node = tempy.nodes[6]\n", + "# plot_look_up_table(node)\n", + "# plot_schemata(node)\n", + "print(node.look_up_table())\n", + "print(node.schemata_look_up_table(type=\"pi\"))\n", + "print(node)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.21875\n" + ] + } + ], + "source": [ + "# find bias of the lut of node\n", + "node.look_up_table()\n", + "print(node.bias())\n" ] }, { @@ -93,59 +167,59 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "# need to modify the output list from data function to include the this following function\n", - "def from_output_list_with_missing_data(outputs=list(), *args, **kwargs):\n", - " \"\"\"\n", - " Instanciate a Boolean Node from a output transition list.\n", + "# # need to modify the output list from data function to include the this following function\n", + "# def from_output_list_with_missing_data(outputs=list(), *args, **kwargs):\n", + "# \"\"\"\n", + "# Instanciate a Boolean Node from a output transition list.\n", "\n", - " For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing.\n", + "# For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing.\n", "\n", - " Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs.\n", + "# Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs.\n", "\n", - " Args:\n", - " outputs (list) : The transition outputs of the node.\n", + "# Args:\n", + "# outputs (list) : The transition outputs of the node.\n", "\n", - " Returns:\n", - " (BooleanNode) : the instanciated object.\n", + "# Returns:\n", + "# (BooleanNode) : the instanciated object.\n", "\n", - " Example:\n", - " >>> BooleanNode.from_output_list_with_missing_data(outputs=[0,0,0,'-',1], name=\"AND\")\n", - " \"\"\"\n", - " id = kwargs.pop(\"id\") if \"id\" in kwargs else 0\n", - " name = kwargs.pop(\"name\") if \"name\" in kwargs else \"x\"\n", - " k = int(np.ceil(np.log2(len(outputs))))\n", - " inputs = kwargs.pop(\"inputs\") if \"inputs\" in kwargs else [(x + 1) for x in range(k)]\n", - " state = kwargs.pop(\"state\") if \"state\" in kwargs else False\n", + "# Example:\n", + "# >>> BooleanNode.from_output_list_with_missing_data(outputs=[0,0,0,'-',1], name=\"AND\")\n", + "# \"\"\"\n", + "# id = kwargs.pop(\"id\") if \"id\" in kwargs else 0\n", + "# name = kwargs.pop(\"name\") if \"name\" in kwargs else \"x\"\n", + "# k = int(np.ceil(np.log2(len(outputs))))\n", + "# inputs = kwargs.pop(\"inputs\") if \"inputs\" in kwargs else [(x + 1) for x in range(k)]\n", + "# state = kwargs.pop(\"state\") if \"state\" in kwargs else False\n", "\n", - " # Replace 'None', '-', '#', or 'x' with '-'.\n", - " for i in range(len(outputs)):\n", - " if outputs[i] in [None, \"-\", \"#\", \"x\"]:\n", - " outputs[i] = \"-\" # Placeholder value for missing data\n", - " print(\n", - " \"Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.\"\n", - " )\n", + "# # Replace 'None', '-', '#', or 'x' with '-'.\n", + "# for i in range(len(outputs)):\n", + "# if outputs[i] in [None, \"-\", \"#\", \"x\"]:\n", + "# outputs[i] = \"-\" # Placeholder value for missing data\n", + "# print(\n", + "# \"Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.\"\n", + "# )\n", "\n", - " # Generate extra lines in the table to account for missing lines\n", - " if len(outputs) < 2**k:\n", - " print(\n", - " f\"Some of the lines in the data are missing and have been replaced with the placeholder value '-' for upto 2^k lines. i.e. the total lines inputted are {len(outputs)}, then the function will generate the missing rows for upto 2^{k} = {2**k} lines.\"\n", - " )\n", - " outputs.extend([\"-\"] * (2**k - len(outputs)))\n", + "# # Generate extra lines in the table to account for missing lines\n", + "# if len(outputs) < 2**k:\n", + "# print(\n", + "# f\"Some of the lines in the data are missing and have been replaced with the placeholder value '-' for upto 2^k lines. i.e. the total lines inputted are {len(outputs)}, then the function will generate the missing rows for upto 2^{k} = {2**k} lines.\"\n", + "# )\n", + "# outputs.extend([\"-\"] * (2**k - len(outputs)))\n", "\n", - " return BooleanNode(\n", - " id=id,\n", - " name=name,\n", - " k=k,\n", - " inputs=inputs,\n", - " state=state,\n", - " outputs=outputs,\n", - " *args,\n", - " **kwargs,\n", - " )\n", + "# return BooleanNode(\n", + "# id=id,\n", + "# name=name,\n", + "# k=k,\n", + "# inputs=inputs,\n", + "# state=state,\n", + "# outputs=outputs,\n", + "# *args,\n", + "# **kwargs,\n", + "# )\n", "\n", "\n", "# def generate_output_list_permutations(incomplete_boolean_node):\n", @@ -170,9 +244,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 0, None, 1, 1, 0]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "incomplete_output = [0, 0, None, 1, 1, 0]\n", "# incomplete_output = tempy.nodes[5].outputs.copy()\n", @@ -180,8 +265,8 @@ "\n", "\n", "# creating a boolean node for incomplete data\n", - "incomplete_boolean_node = from_output_list_with_missing_data(incomplete_output)\n", - "print(incomplete_boolean_node)\n", + "# incomplete_boolean_node = from_output_list_with_missing_data(incomplete_output)\n", + "# print(incomplete_boolean_node)\n", "# output_list_permutations = generate_output_list_permutations(incomplete_boolean_node)\n", "# print(f'Following are the pemutations of the incomplete output list of length:{len(output_list_permutations)}')\n", "# output_list_permutations" @@ -189,11 +274,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "incomplete_boolean_node.look_up_table()" + "# incomplete_boolean_node.look_up_table()" ] }, { @@ -205,9 +290,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Input Output\n", + "0 #0 0\n", + "1 #1 1\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " In: Out:\n", + "0 00 0\n", + "1 01 1\n", + "2 10 0\n", + "3 11 1\n" + ] + } + ], "source": [ "# # testing modified from_output_list function\n", "# incomplete_output = [0,0, None, 1,1,0]\n", @@ -222,22 +338,58 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('00--', '0'), ('1--1', '1'), ('11--', '0')]\n", + "The LUT is incomplete. Missing values are represented by '?'\n", + "[('0000', '0'), ('0001', '0'), ('0010', '0'), ('0011', '0'), ('0100', '?'), ('0101', '?'), ('0110', '?'), ('0111', '?'), ('1000', '?'), ('1001', '1'), ('1010', '?'), ('1011', '1'), ('1100', '0'), ('1101', '!'), ('1110', '0'), ('1111', '!')]\n" + ] + } + ], "source": [ "# # partial_lut = [('1--','1'),('101','0'),('011','0'),('01-','1')]\n", "# # partial_lut = [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')]\n", - "partial_lut = [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"0\")]\n", + "partial_lut = [('00--', '0'), ('1--1', '1'), ('11--', '0')]\n", + "# partial_lut = [('00--', '0'), ('01--', '1'), ('10--', '1'), ('11--', '0')]\n", + "print(partial_lut)\n", "generated_lut = fill_out_lut(partial_lut)\n", - "generated_lut" + "print(generated_lut)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('---1', '0'), ('-1--', '0'), ('1---', '0'), ('--1-', '0'), ('0000', '1')]\n", + "0000 0\n", + "0001 0\n", + "0010 0\n", + "0011 0\n", + "0100 ?\n", + "0101 ?\n", + "0110 ?\n", + "0111 ?\n", + "1000 ?\n", + "1001 1\n", + "1010 ?\n", + "1011 1\n", + "1100 1\n", + "1101 1\n", + "1110 1\n", + "1111 1\n" + ] + } + ], "source": [ "# write a function that converts datya in the example form 00-- 0\\n1--1 1\\n11-- 0 to this example form: ('00--','0'),('1--1','1'),('11--','0')\n", "def from_example_form_to_list(example_form):\n", @@ -246,7 +398,7 @@ " return example_form\n", "\n", "\n", - "print(from_example_form_to_list(\"###1 0\\n#1## 0\\n1### 0\\n##1# 0\\n0000 1\"))\n", + "print(from_example_form_to_list(\"---1 0\\n-1-- 0\\n1--- 0\\n--1- 0\\n0000 1\"))\n", "\n", "\n", "# write a function that converts data in the example form ('00--','0'),('1--1','1'),('11--','0') to this example form: 00-- 0\\n1--1 1\\n11-- 0\n", @@ -256,20 +408,304 @@ " return example_form\n", "\n", "\n", - "# print(from_list_to_example_form(partial_lut))" + "print(from_list_to_example_form(generated_lut))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16\n" + ] + }, + { + "data": { + "text/plain": [ + "['0',\n", + " '0',\n", + " '0',\n", + " '0',\n", + " '?',\n", + " '?',\n", + " '?',\n", + " '?',\n", + " '?',\n", + " '1',\n", + " '?',\n", + " '1',\n", + " '1',\n", + " '1',\n", + " '1',\n", + " '1']" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(generated_lut))\n", + "output = []\n", + "output = [generated_lut[i][1] for i in range(len(generated_lut))]\n", + "output\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, "metadata": { "vscode": { "languageId": "shellscript" } }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
In:Out:
000000
100010
200100
300110
40100?
50101?
60110?
70111?
81000?
910011
101010?
1110111
1211001
1311011
1411101
1511111
\n", + "
" + ], + "text/plain": [ + " In: Out:\n", + "0 0000 0\n", + "1 0001 0\n", + "2 0010 0\n", + "3 0011 0\n", + "4 0100 ?\n", + "5 0101 ?\n", + "6 0110 ?\n", + "7 0111 ?\n", + "8 1000 ?\n", + "9 1001 1\n", + "10 1010 ?\n", + "11 1011 1\n", + "12 1100 1\n", + "13 1101 1\n", + "14 1110 1\n", + "15 1111 1" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generated_lut = fill_out_lut(partial_lut)\n", + "output_list = [x[1] for x in generated_lut]\n", + "print(output_list)\n", + "generated_node = BooleanNode.from_output_list(output_list)\n", + "generated_node.look_up_table()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", + " In: Out:\n", + "0 0000 0\n", + "1 0001 0\n", + "2 0010 0\n", + "3 0011 0\n", + "4 0100 ?\n", + "5 0101 ?\n", + "6 0110 ?\n", + "7 0111 ?\n", + "8 1000 ?\n", + "9 1001 1\n", + "10 1010 ?\n", + "11 1011 1\n", + "12 1100 1\n", + "13 1101 1\n", + "14 1110 1\n", + "15 1111 1\n" + ] + } + ], + "source": [ + "generated_node = BooleanNode.from_partial_lut(partial_lut)\n", + "print(generated_node.outputs)\n", + "print(generated_node.look_up_table())" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['0', '1', '0', '1']" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logic = {\n", + " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", + " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", + " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", + "}\n", + "# Instanciate the BooleanNetwork\n", + "bn = BooleanNetwork.from_dict(logic)\n", + "bn.nodes[0].outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], "source": [ - "\n" + "bn = BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], name=\"EG\")\n", + "print(bn)" ] } ], From 8fc41d8731db01cecdfb2d1d46b78e4ed99de224 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Sun, 16 Jun 2024 21:26:10 -0400 Subject: [PATCH 06/14] added from_partial_lut method in BooleanNode --- cana/boolean_network.py | 4 +- cana/boolean_node.py | 80 ++++- cana/utils.py | 27 +- tutorials/Generating from Partial LUTs.ipynb | 312 ++++++------------- tutorials/temp.ipynb | 89 +++--- 5 files changed, 238 insertions(+), 274 deletions(-) diff --git a/cana/boolean_network.py b/cana/boolean_network.py index 2e0d5f0..08d423f 100644 --- a/cana/boolean_network.py +++ b/cana/boolean_network.py @@ -178,6 +178,8 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): Instanciates a Boolean Network from a string in cnet format. The cnet format is similar to the Berkeley Logic Interchange Format (BLIF). + This function generates a Logic dictionary from the string and uses the :func:`~cana.boolean_network.BooleanNetwork.from_dict` method to generate the Boolean Network object. + Args: string (string): A cnet format representation of a Boolean Network. @@ -294,7 +296,7 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): @classmethod def from_string_boolean(self, string, keep_constants=True, **kwargs): """ - Instanciates a Boolean Network from a Boolean update rules format. + Instanciates a Boolean Network from a Boolean update rules format. Genetates a Logic dictionary from the string and uses the :func:`~cana.boolean_network.BooleanNetwork.from_dict` method to generate the Boolean Network object. Args: string (string) : A boolean update rules format representation of a Boolean Network. diff --git a/cana/boolean_node.py b/cana/boolean_node.py index f80a2f9..c5eb278 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -30,6 +30,7 @@ statenum_to_binstate, ) from cana.utils import input_monotone, ncr, fill_out_lut +import random class BooleanNode(object): @@ -156,27 +157,78 @@ def from_output_list(self, outputs=list(), *args, **kwargs): **kwargs ) - def from_partial_lut(partial_lut, *args, **kwargs): + def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required_node_bias = None, verbose= True, *args, **kwargs): """ - Instanciate a Boolean Node from a partial look-up table. + Instantiate a Boolean Node from a partial look-up table. - Uses the fill_out_lut function to complete the look-up table. Extracts the output list from the completed look-up table. Then instanciates the Boolean Node from the output list using the from_output_list method. + Uses the fill_out_lut function to complete the look-up table. Extracts the output list from the completed look-up table. Then instantiates the Boolean Node from the output list using the from_output_list method. Args: partial_lut (list) : A partial look-up table of the node. + fill_missing_output_randomly (bool) : If True, missing output values are filled with random 0 or 1. If False, missing output values are filled with '?'. + required_node_bias (float) : The required node bias to fill the missing output values with. If None, missing output values are filled with '?', or randomly if fill_missing_output is True. + verbose (bool) : If True, print additional information. Default is True. Returns: - (BooleanNode) : the instanciated object. + (BooleanNode) : the instantiated object. Example: - >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], name="EG") - + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], required_node_bias=0.5, verbose=True, name="EG") + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], fill_missing_output_randomly=True, verbose=False, name="EG") + # TODO : [SRI] add tests for this """ + - generated_lut = fill_out_lut(partial_lut) + generated_lut = fill_out_lut(partial_lut, verbose=verbose) output_list = [x[1] for x in generated_lut] - return BooleanNode.from_output_list(output_list, *args, **kwargs) + generated_node = BooleanNode.from_output_list(output_list, *args, **kwargs) + + # Fill missing output values with the specified bias or randomly + + if required_node_bias is not None: # If required node bias is specified, then fill missing output values with the specified bias. + + # Checking if required node bias is within the achievable bias range of the node. + + # Calculating max achievable bias + max_achievable_output = ['1' if output == '?' else output for output in generated_node.outputs] + max_achievable_bias = sum(map(int, max_achievable_output))/2**generated_node.k + min_achievable_bias = generated_node.bias(verbose=False) + + # Calculating the number of '1' required to achieve the required bias. + required_ones = int(required_node_bias * 2**generated_node.k) + current_ones = generated_node.outputs.count('1') + + # Checking if the required bias is achievable. + if required_node_bias > max_achievable_bias: + if verbose: + print(f"Required Node Bias is greater than the maximum achievable bias ({max_achievable_bias}) of the node. Generating with the maximum achievable bias.") + required_node_bias = max_achievable_bias + + elif required_node_bias < min_achievable_bias: + min_achievable_bias = generated_node.bias(verbose=False) + if verbose: + print(f"Required Node Bias is lower than the minimum achievable bias (bias = {min_achievable_bias}) of the node. Generating with the minimum achievable bias.") + required_node_bias = min_achievable_bias + + # Fill the missing output values to achieve the required bias as closely as possible. + required_ones = int(required_node_bias * 2**generated_node.k) # recalculating in case the required bias was adjusted in the above steps. + ones_to_be_generated = required_ones - current_ones + number_of_missing_values = generated_node.outputs.count('?') + + missing_output_values = ['1'] * ones_to_be_generated + ['0'] * (number_of_missing_values - ones_to_be_generated) # creating a shuffled list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias. + random.shuffle(missing_output_values) + generated_node.outputs = [missing_output_values.pop() if output== '?' else output for output in generated_node.outputs] + + if verbose: + print(f"Generated the node with a bias of {generated_node.bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {required_node_bias}.") + + else: + if fill_missing_output_randomly: + # Replace '?' in generated_node.outputs with 0 or 1 randomly + generated_node.outputs = [random.choice(['0', '1']) if output == '?' else output for output in generated_node.outputs] + + return generated_node @@ -857,7 +909,7 @@ def _check_compute_canalization_variables(self, **kwargs): raise Exception("Canalization variable name not found. %s" % kwargs) return True - def bias(self): + def bias(self, verbose=True): r"""The node bias. The sum of the boolean output transitions divided by the number of entries (:math:`2^k`) in the LUT. .. math:: @@ -870,7 +922,15 @@ def bias(self): See Also: :func:`~cana.boolean_network.BooleanNetwork.network_bias` """ - return sum(map(int, self.outputs)) / 2**self.k + if verbose: + if '?' in self.outputs: + print("Warning: There is a '?' value in the output. It will be treated as zero for the bias calculation.") + + outputs = [0 if output == '?' else output for output in self.outputs] # added this condition so that bias function plays nice with '?' output values. It will treat missing outputs as 0. + + bias = sum(map(int, outputs)) / 2**self.k + + return bias def c_sensitivity(self, c, mode="default", max_k=0): """Node c-sensitivity. diff --git a/cana/utils.py b/cana/utils.py index 8d31334..2b1129c 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -328,12 +328,16 @@ def input_monotone(outputs, input_idx, activation=1): return all(monotone_configs) -def fill_out_lut(partial_lut): +def fill_out_lut(partial_lut, verbose= False): """ Fill out a partial LUT with missing entries. Args: partial_lut (list) : A list of tuples where each tuple is a pair of a binary string and a value. + fill_missing_output (bool) : If True, missing output values are filled with random 0 or 1. If False, missing output values are filled with '?'. + + + Returns: (list) : A list of tuples where each tuple is a pair of a binary string and a value. @@ -342,9 +346,6 @@ def fill_out_lut(partial_lut): >>> fill_out_lut([('00', 0), ('01', 0), ('1-', 1), ('11', 1)]) [('00', 0), ('01', 0), ('10', 1), ('11', 1)] - # TODO: [SRI] update function to handle txt file input style to generate the partial LUT - # TODO: [SRI] fill up '?' symbols based on specified criteria- a coin toss, or specified bias - # TODO: [SRI] add bias criteria to handle incomplete output values # TODO: [SRI] generate LUT with a specified effective connectivity # TODO: [SRI] generate LUT from two symbol schemata, with a specified ratio of wildcard symbols # TODO: [SRI] add tests for canonical rule logic, rule 90, rule 110 @@ -378,7 +379,7 @@ def fill_out_lut(partial_lut): for perm in output_list_permutations: if perm in all_states and all_states[perm] != entry[1]: - # print('Clashing output values for entry:', perm) + print('Clashing output values for entry:', perm) all_states[perm] = '!' else: all_states[perm] = entry[1] @@ -386,13 +387,15 @@ def fill_out_lut(partial_lut): for i in range(2**k): state = bin(i)[2:].zfill(k) if state not in all_states: - all_states[state] = '?' # TODO: [SRI] Add option to generate 0 or 1 with 0.5 probability - - # Print a statement if there are any missing values '?' in the LUT. Else print a statement that the LUT is complete. - if '?' in all_states.values(): - print('The LUT is incomplete. Missing values are represented by \'?\'') - else: - print('The LUT is complete.') + all_states[state] = '?' + + if verbose: + # Print a statement if there are any missing values '?' in the LUT. Else print a statement that the LUT is complete. + if '?' in all_states.values(): + print('The LUT is incomplete. Missing values are represented by \'?\'') + else: + print('The LUT is complete.') all_states = sorted(all_states.items(), key=lambda x: x[0]) + return all_states \ No newline at end of file diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index 6a91bff..e82e4ca 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -20,16 +20,9 @@ "from cana.utils import fill_out_lut\n", "\n", "from cana.boolean_node import BooleanNode\n", - "\n" + "from cana.boolean_network import BooleanNetwork" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -45,9 +38,17 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 2, "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Clashing output values for entry: 101\n", + "Clashing output values for entry: 011\n" + ] + }, { "data": { "text/plain": [ @@ -61,7 +62,7 @@ " ('111', '1')]" ] }, - "execution_count": 24, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -71,8 +72,8 @@ "\n", "partial_luts = [\n", " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [('1--','1'),('101','0'),('011','0'),('01-','1')],\n", - " [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", "]\n", "generated_lut = fill_out_lut(partial_luts[1])\n", "generated_lut" @@ -82,7 +83,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Partial LUTs in BNS format\n", + "## Partial LUTs in BNS (.cnet) format\n", "\n", "BNS is a software tool for computing attractors in Boolean Networks with Synchronous update. Synchronous Boolean networks are used for the modeling of genetic regulatory networks.\n", "\n", @@ -93,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -101,7 +102,15 @@ "output_type": "stream", "text": [ "Entry clash in node 5 for {'000'} i.e. State number: 0\n", - "\n" + "\n", + " In: Out:\n", + "0 00 0\n", + "1 01 1\n", + "2 10 ?\n", + "3 11 1\n", + " Input Output\n", + "0 00 0\n", + "1 #1 1\n" ] }, { @@ -126,13 +135,15 @@ } ], "source": [ - "partial_luts = PARTIAL_LUTS_DEMO() # Instantiating a sample partial_luts dataset from the dataset folder.\n", + "partial_luts = (\n", + " PARTIAL_LUTS_DEMO()\n", + ") # Instantiating a sample partial_luts dataset from the dataset folder.\n", "\n", "node = partial_luts.nodes[5]\n", "\n", "print(node)\n", - "# print(node.look_up_table())\n", - "# print(node.schemata_look_up_table())\n", + "print(node.look_up_table())\n", + "print(node.schemata_look_up_table())\n", "\n", "plot_look_up_table(node)\n", "plot_schemata(node)" @@ -140,12 +151,29 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Warning: There is a '?' value in the output. It will be treated as zero for the bias calculation.\n" + ] + }, + { + "data": { + "text/plain": [ + "0.5" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "# plot_schemata(node)\n", - "# plot_look_up_table(node)" + "node.bias()" ] }, { @@ -158,226 +186,90 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['?', '?', '1', '!', '1', '!', '1', '1']\n" + "The LUT is incomplete. Missing values are represented by '?'\n", + "Generated the node with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.44.\n", + "\n", + "['0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '1', '0', '1', '0', '1', '0']\n" ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
In:Out:
0000?
1001?
20101
3011!
41001
5101!
61101
71111
\n", - "
" - ], - "text/plain": [ - " In: Out:\n", - "0 000 ?\n", - "1 001 ?\n", - "2 010 1\n", - "3 011 !\n", - "4 100 1\n", - "5 101 !\n", - "6 110 1\n", - "7 111 1" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "\n", - "\n", "partial_luts = [\n", " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [('1--','1'),('101','0'),('011','0'),('01-','1')],\n", - " [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", "]\n", - "partial_lut = partial_luts[1]\n", - "\n", + "partial_lut = partial_luts[2]\n", "\n", + "\"\"\"\n", "generated_lut = fill_out_lut(partial_lut) # Using the fill_out_lut function found in utils.py\n", "output_list = [x[1] for x in generated_lut] # Extracting the output values from the generated_lut\n", "print(output_list)\n", "generated_node = BooleanNode.from_output_list(output_list) # Instantiating a BooleanNode object from the output_list\n", - "generated_node.look_up_table() # Displaying the look-up table of the generated_node" + "generated_node.look_up_table() # Displaying the look-up table of the generated_node\n", + "\"\"\"\n", + "\n", + "# Combining the above functions into a single function under BooleanNode class\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.44)\n", + "print(generated_node)\n", + "print(generated_node.outputs)\n", + "# print(f\"Bias = {generated_node.bias()}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiating a Boolean Network \n", + "\n", + "The Boolean Network is created using the BooleanNetwork.from_dict() function which takes a Logic Dictionary as input. \n", + "\n", + "The logic dict is in the following format:\n", + "\n", + "```python\n", + "logic = {\n", + " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", + " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", + " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", + " }\n", + "```" ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" + "{0: {'name': 'x', 'in': [1, 2, 3, 4], 'out': ['0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '1', '0', '1', '0', '1', '0']}}\n" ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
In:Out:
0000?
1001?
20101
3011!
41001
5101!
61101
71111
\n", - "
" - ], - "text/plain": [ - " In: Out:\n", - "0 000 ?\n", - "1 001 ?\n", - "2 010 1\n", - "3 011 !\n", - "4 100 1\n", - "5 101 !\n", - "6 110 1\n", - "7 111 1" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "# Combining the above functions into a single function under BooleanNode class\n", + "def generate_logic_dict_from_boolean_node(boolean_node, k = 5, nnodes= 8):\n", + " \n", + " logic = {}\n", + " \n", + " logic= { 0: {\n", + " 'name': boolean_node.name,\n", + " 'in': [input_node for input_node in boolean_node.inputs],\n", + " 'out': boolean_node.outputs\n", + " }\n", + " }\n", + " return logic\n", "\n", - "generated_node = BooleanNode.from_partial_lut(partial_lut) \n", - "print(generated_node)\n", - "generated_node.look_up_table()\n" + "logic = generate_logic_dict_from_boolean_node(generated_node)\n", + "print(logic)" ] } ], diff --git a/tutorials/temp.ipynb b/tutorials/temp.ipynb index 4ccbd38..6712de8 100644 --- a/tutorials/temp.ipynb +++ b/tutorials/temp.ipynb @@ -109,22 +109,22 @@ "\n", "[64 rows x 2 columns]\n", " Input Output\n", - "0 ##0### 0\n", + "0 0##000 0\n", "1 #1#### 0\n", - "2 0##000 0\n", - "3 1##111 0\n", - "4 001##1 1\n", - "5 101#0# 1\n", - "6 #011#0 1\n", - "7 0011## 1\n", - "8 #01#01 1\n", - "9 #0110# 1\n", - "10 #0101# 1\n", - "11 #010#1 1\n", - "12 001#1# 1\n", - "13 #01#10 1\n", - "14 1010## 1\n", - "15 101##0 1\n", + "2 1##111 0\n", + "3 ##0### 0\n", + "4 1010## 1\n", + "5 #01#10 1\n", + "6 0011## 1\n", + "7 #0101# 1\n", + "8 001#1# 1\n", + "9 #011#0 1\n", + "10 001##1 1\n", + "11 101##0 1\n", + "12 #01#01 1\n", + "13 #010#1 1\n", + "14 #0110# 1\n", + "15 101#0# 1\n", "\n" ] } @@ -338,7 +338,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -346,7 +346,8 @@ "output_type": "stream", "text": [ "[('00--', '0'), ('1--1', '1'), ('11--', '0')]\n", - "The LUT is incomplete. Missing values are represented by '?'\n", + "Clashing output values for entry: 1101\n", + "Clashing output values for entry: 1111\n", "[('0000', '0'), ('0001', '0'), ('0010', '0'), ('0011', '0'), ('0100', '?'), ('0101', '?'), ('0110', '?'), ('0111', '?'), ('1000', '?'), ('1001', '1'), ('1010', '?'), ('1011', '1'), ('1100', '0'), ('1101', '!'), ('1110', '0'), ('1111', '!')]\n" ] } @@ -383,10 +384,10 @@ "1001 1\n", "1010 ?\n", "1011 1\n", - "1100 1\n", - "1101 1\n", - "1110 1\n", - "1111 1\n" + "1100 0\n", + "1101 !\n", + "1110 0\n", + "1111 !\n" ] } ], @@ -438,10 +439,10 @@ " '1',\n", " '?',\n", " '1',\n", - " '1',\n", - " '1',\n", - " '1',\n", - " '1']" + " '0',\n", + " '!',\n", + " '0',\n", + " '!']" ] }, "execution_count": 14, @@ -469,7 +470,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n" + "Clashing output values for entry: 1101\n", + "Clashing output values for entry: 1111\n", + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '0', '!', '0', '!']\n" ] }, { @@ -561,22 +564,22 @@ " \n", " 12\n", " 1100\n", - " 1\n", + " 0\n", " \n", " \n", " 13\n", " 1101\n", - " 1\n", + " !\n", " \n", " \n", " 14\n", " 1110\n", - " 1\n", + " 0\n", " \n", " \n", " 15\n", " 1111\n", - " 1\n", + " !\n", " \n", " \n", "\n", @@ -596,10 +599,10 @@ "9 1001 1\n", "10 1010 ?\n", "11 1011 1\n", - "12 1100 1\n", - "13 1101 1\n", - "14 1110 1\n", - "15 1111 1" + "12 1100 0\n", + "13 1101 !\n", + "14 1110 0\n", + "15 1111 !" ] }, "execution_count": 15, @@ -617,7 +620,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 16, "metadata": { "vscode": { "languageId": "shellscript" @@ -628,7 +631,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", + "Clashing output values for entry: 1101\n", + "Clashing output values for entry: 1111\n", + "The LUT is incomplete. Missing values are represented by '?'\n", + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '0', '!', '0', '!']\n", " In: Out:\n", "0 0000 0\n", "1 0001 0\n", @@ -642,10 +648,10 @@ "9 1001 1\n", "10 1010 ?\n", "11 1011 1\n", - "12 1100 1\n", - "13 1101 1\n", - "14 1110 1\n", - "15 1111 1\n" + "12 1100 0\n", + "13 1101 !\n", + "14 1110 0\n", + "15 1111 !\n" ] } ], @@ -688,7 +694,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 18, "metadata": { "vscode": { "languageId": "shellscript" @@ -699,6 +705,7 @@ "name": "stdout", "output_type": "stream", "text": [ + "The LUT is incomplete. Missing values are represented by '?'\n", "\n" ] } From e09f217d352884d1364639ba8c6f0b7dce656e87 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 17 Jun 2024 18:00:08 -0400 Subject: [PATCH 07/14] added required effective connectivity criterion to BooleanNode.from_partial_lut() --- cana/boolean_node.py | 58 +++- cana/drawing/schema_vis.py | 4 + cana/utils.py | 3 +- tutorials/Generating from Partial LUTs.ipynb | 287 ++++++++++++++++--- tutorials/temp.ipynb | 50 ++++ 5 files changed, 350 insertions(+), 52 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index c5eb278..e78aaea 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -157,7 +157,7 @@ def from_output_list(self, outputs=list(), *args, **kwargs): **kwargs ) - def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required_node_bias = None, verbose= True, *args, **kwargs): + def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required_node_bias = None, required_effective_connectivity= None,verbose= True, *args, **kwargs): """ Instantiate a Boolean Node from a partial look-up table. @@ -167,6 +167,7 @@ def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required partial_lut (list) : A partial look-up table of the node. fill_missing_output_randomly (bool) : If True, missing output values are filled with random 0 or 1. If False, missing output values are filled with '?'. required_node_bias (float) : The required node bias to fill the missing output values with. If None, missing output values are filled with '?', or randomly if fill_missing_output is True. + required_effective_connectivity (float) : The required effective connectivity to fill the missing output values with. It will generate a node with the closest possible effective connectivity to the required effective connectivity. verbose (bool) : If True, print additional information. Default is True. Returns: @@ -175,16 +176,28 @@ def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required Example: >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], required_node_bias=0.5, verbose=True, name="EG") >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], fill_missing_output_randomly=True, verbose=False, name="EG") + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], required_effective_connectivity=0.5, verbose=True, name="EG") + + Note: + The partial look-up table should be a list of tuples where each tuple contains a binary input state and the corresponding output value. For example, [('00', 0), ('01', 1), ('11', 1)]. + The required node bias should be a float value between 0 and 1. + The required effective connectivity should be a float value between 0 and 1. + The fill_missing_output_randomly should be a boolean value. + # TODO : [SRI] add tests for this """ + # Checking if more than one out of required_effective_connectivity, requried_node_bias and fill_missing_output_randomly are True, then raise an error. + if sum([required_effective_connectivity is not None, required_node_bias is not None, fill_missing_output_randomly]) > 1: + raise ValueError("Only one of required_effective_connectvity, required_node_bias and fill_missing_output_randomly can be True. Please set the rest to False.") + - generated_lut = fill_out_lut(partial_lut, verbose=verbose) + generated_lut = fill_out_lut(partial_lut, verbose=False) output_list = [x[1] for x in generated_lut] generated_node = BooleanNode.from_output_list(output_list, *args, **kwargs) - # Fill missing output values with the specified bias or randomly + # Fill missing output values with the specified bias or with specified effective connectivity or randomly if required_node_bias is not None: # If required node bias is specified, then fill missing output values with the specified bias. @@ -223,11 +236,37 @@ def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required if verbose: print(f"Generated the node with a bias of {generated_node.bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {required_node_bias}.") - else: - if fill_missing_output_randomly: - # Replace '?' in generated_node.outputs with 0 or 1 randomly - generated_node.outputs = [random.choice(['0', '1']) if output == '?' else output for output in generated_node.outputs] + elif fill_missing_output_randomly: + # Replace '?' in generated_node.outputs with 0 or 1 randomly + generated_node.outputs = [random.choice(['0', '1']) if output == '?' else output for output in generated_node.outputs] + elif required_effective_connectivity is not None: + generated_outputs = generated_node.outputs.copy() + missing_output_indices = [i for i, x in enumerate(generated_outputs) if x == '?'] + # print(f"Missing output indices = {missing_output_indices}." if verbose else None) + + missing_output_count = generated_outputs.count('?') + # print(f"No. of '?' in output = {missing_output_count}.") + permutations = list(product(*[('0', '1')] * (missing_output_count))) + # print(permutations) + generated_node_permutations = [None] * len(permutations) + + for count, permutation in enumerate(permutations): + for i, index in enumerate(missing_output_indices): + generated_outputs[index] = permutation[i] + generated_node_permutations[count] = BooleanNode.from_output_list(generated_outputs) + + # print(f"Total output permutations generated = {len(generated_node_permutations)}.") + + permutation_effective_connectivity = [x.effective_connectivity() for x in generated_node_permutations] + closest_value = min(permutation_effective_connectivity, key=lambda x: abs(x - required_effective_connectivity)) + closest_index = permutation_effective_connectivity.index(closest_value) + + generated_node = generated_node_permutations[closest_index] + print(f"Generated the node with the closest possible effective connectivity of {generated_node.effective_connectivity()}." if verbose else None) + + if '?' in generated_node.outputs: + print("The LUT is incomplete. Missing values are represented by '?'." if verbose else None) return generated_node @@ -541,6 +580,11 @@ def schemata_look_up_table( See also: :func:`look_up_table` """ + # Check if the outputs contain '?' and generate an error message if it does. + if '?' in self.outputs: + print("Error (schemata_look_up_table): The outputs contain missing values. Please fill the missing values before generating the schemata look-up table.") + return False + r = [] # Prime Implicant LUT if type == "pi": diff --git a/cana/drawing/schema_vis.py b/cana/drawing/schema_vis.py index f9e3373..d6b8a67 100644 --- a/cana/drawing/schema_vis.py +++ b/cana/drawing/schema_vis.py @@ -11,6 +11,10 @@ def plot_schemata(n, plotTS=True): # Init values from BooleanNode k = n.k if n.k >= 1 else 1 outputs = np.array(n.outputs) + + if "?" in outputs: # check if there are any '?' in the output. + print("Error (plot_schemata()): The output contains '?'") + return False if np.all(outputs[0] == outputs): return False inputs = n.inputs if not n.constant else [n.name] diff --git a/cana/utils.py b/cana/utils.py index 2b1129c..962c216 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -398,4 +398,5 @@ def fill_out_lut(partial_lut, verbose= False): all_states = sorted(all_states.items(), key=lambda x: x[0]) - return all_states \ No newline at end of file + return all_states + diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index e82e4ca..fa6562b 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -19,8 +19,7 @@ "from cana.drawing.plot_look_up_table import plot_look_up_table\n", "from cana.utils import fill_out_lut\n", "\n", - "from cana.boolean_node import BooleanNode\n", - "from cana.boolean_network import BooleanNetwork" + "from cana.boolean_node import BooleanNode" ] }, { @@ -108,9 +107,8 @@ "1 01 1\n", "2 10 ?\n", "3 11 1\n", - " Input Output\n", - "0 00 0\n", - "1 #1 1\n" + "Error (schemata_look_up_table): The outputs contain missing values. Please fill the missing values before generating the schemata look-up table.\n", + "False\n" ] }, { @@ -123,15 +121,22 @@ "metadata": {}, "output_type": "display_data" }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Error (plot_schemata()): The output contains '?'\n" + ] + }, { "data": { - "image/png": "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", "text/plain": [ - "
" + "False" ] }, + "execution_count": 3, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ @@ -143,10 +148,10 @@ "\n", "print(node)\n", "print(node.look_up_table())\n", - "print(node.schemata_look_up_table())\n", + "print(node.schemata_look_up_table()) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table.\n", "\n", "plot_look_up_table(node)\n", - "plot_schemata(node)" + "plot_schemata(node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." ] }, { @@ -181,7 +186,8 @@ "metadata": {}, "source": [ "## Instantiating a BooleanNode object using partial LUT\n", - "\n" + "\n", + "Incorporating the fill_out_lut() function into the instantiation of a single boolean node object under the class BooleanNode, this object will now contain '?' for unspecified output values in the LUT entry. \n" ] }, { @@ -193,11 +199,35 @@ "name": "stdout", "output_type": "stream", "text": [ - "The LUT is incomplete. Missing values are represented by '?'\n", - "Generated the node with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.44.\n", - "\n", - "['0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '1', '0', '1', '0', '1', '0']\n" + "\n" ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Error (plot_schemata()): The output contains '?'\n" + ] + }, + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -205,8 +235,10 @@ " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " \n", "]\n", - "partial_lut = partial_luts[2]\n", + "partial_lut = partial_luts[3]\n", "\n", "\"\"\"\n", "generated_lut = fill_out_lut(partial_lut) # Using the fill_out_lut function found in utils.py\n", @@ -217,59 +249,226 @@ "\"\"\"\n", "\n", "# Combining the above functions into a single function under BooleanNode class\n", - "generated_node = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.44)\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut) \n", "print(generated_node)\n", - "print(generated_node.outputs)\n", - "# print(f\"Bias = {generated_node.bias()}\")" + "# print(generated_node.outputs)\n", + "plot_look_up_table(generated_node)\n", + "plot_schemata(generated_node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Instantiating a Boolean Network \n", + "## Generating LUT with specified Node Bias\n", "\n", - "The Boolean Network is created using the BooleanNetwork.from_dict() function which takes a Logic Dictionary as input. \n", - "\n", - "The logic dict is in the following format:\n", + "The BooleanNode object calculates the node bias using the .bias() function. \n", "\n", "```python\n", - "logic = {\n", - " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", - " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", - " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", - " }\n", - "```" + "generated_node.bias()\n", + "```\n" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{0: {'name': 'x', 'in': [1, 2, 3, 4], 'out': ['0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '1', '0', '1', '0', '1', '0']}}\n" + "Generated the node with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "\n" ] + }, + { + "data": { + "image/png": "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GFq2bBk8PT2xZcsWhaNT3m9+8xt89913bXqPTz75BPfdd5/9/Yzg6aefxiOPPIIVK1bYR4Ci+n7961+36nU9evTAwYMHFY6GiIioZUySXn7WJSIiIiIip+DlRkREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEiGRQIREREREcmwSCAiIiIiIhkWCUREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZHgRP3790f//v21DsMpRGorwPZSy3D9ERGRq2ORQEREREREMiwSiIiIiIhIhkUCERERERHJsEggIiIiIiIZFglERERERCTDIoGIiIiIiGRMkiRJWgfhbDExMTh06JDWYRBRC1ksFnz66acwmUxtfi9JkvCLX/xCuFxgsViQlZWldRhEROTihCwSlPiCQUTaKCsrg9lsbvP7WK1W+Pn5KRCR/giY9omIqIU8tA5AS3v37oWPj4/WYajq8uXLiI+PBwAUFxcr8uXKVZWUlKBXr15ah6EJo/flGzduYPjw4aq9v9H3DaC2KAoJCdE6DCIi0gmhiwQfHx9Df7ECIGuf2Ww29BchI7ftdkToy2oy+r5BRETUUrxxmYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEiGRQIREREREcmwSCAiIiIiIhkWCUREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEhG0yJh9OjRmDlzppYhEBERERFRHZoVCVeuXMGuXbvg6empVQhERERERNQAzYqEzMxM1NTUICEhQasQiIiIiIioAZoVCQcOHMCQIUMQHh6uVQhERERERNQAzYqEgwcP4umnn9bq44mIiIiIqBGaFAmlpaU4c+YMxo8fr8XHExERERFRE1QvEgoLCzF79mwMGDAA/v7+cHNzQ1BQEKqrq9G+fXu1P95lTJ8+HdHR0Xj55Zdl0w8cOIDo6GhER0ejqKhIo+iUU1lZiTVr1uCBBx5AcHAwfH190adPH8ycOROnT5/WOjxVRERE4KuvvoIkScjIyNA6HNWJ0pfVIOL+QURE+uSh5ptnZWXhkUcegdVqrTdv6NChan60S6mqqkJeXh4AYPDgwbJ5R44cAQB06dIFd955p9NjU1JRUREeffRR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6RUVFfY2GeW0s42e+rKrjXRho6d12BJtzflGYtRt3BTmfOZ8o/RlpRllHSr6bdy2M7V2h1m7di0A4De/+Y1iMWmpa9euOHz4MNLS0rBp0yZs2rQJVqsV3bp1w/Tp0zFr1iz07dtX6zAV8+qrr6Jnz571poeGhmLJkiX2///444+6PWDYvhRFRETIitljx46hqqoKQP1T0kagl75sG+kiMTERhYWFGDNmjOYjXdjoZR22RFtzvtEYcRs3hTmfOZ8aZ4R1aJIkSdI6CADYunUrfve736F79+44duyYqg+VMJlMAICysjKXPcWjlJKSEpe8Y15tn376KXx8fLQOQ1WXL1/G8OHDARi/L1utVvj5+QFQrq1qvKcrc2yvlmn/xIkTiIiIwC9/+UscOHDAKZ9p+6Vu69at8Pb2dspnaqW0tBQTJ04EUPsLvu3GWiPy9PS058D58+fbr0YwqrKyMnvxZfS+XFFRYT8LrFRb1XhPV+bY3h07drTqPVziAtFPPvkEEydOREBAALZv3+6ST50jIiIiIhKF5kVCeno64uPj4e/vj/379xvytB0RERERkZ5oWiS8//77GDt2LO644w4cOHCABQIRERERkQvQrEhYu3YtnnzySdx5553IzMxE//79tQqFiIiIiIgcaFIkvP3225g2bRruuusuZGZm4u6779YiDCIiIiIiaoDTH0jw7rvv4qWXXgIAxMbGYv369fWWCQwMxB//+EcnR0ZERGrYvn07tm/fDqB29B2g9iFVkyZNsi+zYcMGp8dFRESNc3qRUFhYaP/b9lyEun72s5+xSCAiMoijR4/iH//4h2xacXGxbBqLBCIi1+L0y42SkpIgSVKT/86ePevssIiISCXNyftERORaNB8ClYiIiIiIXAuLBCIiIiIikmGRQEREREREMiwSiIiIiIhIhkUCERERERHJOH0IVFditVq1DkF1IrSxITdu3NA6BNU5ttHo21nt9hl9/QFitPF2KioqtA5BdY5tdHd31zAS9Tm279atWxpG4hyObTR6X1a7fUZff4AybTRJAo49ZzKZtA6BiFqprKwMZrO5ze9jtVrh5+enQET6I1raj4uL0zoEImqlrVu3wtvbu83vU1FRgXHjxikQkf7s2LGjVa8T8nIji8WidQhE1AoWiwW+vr6KvJevr6+QuUDENoeFhWkdAhG1QlhYGLy8vBR5Ly8vLyFzQVvaLOSZBEmSUF5ernUYTmPbxCKcQRGprYB47fX19VW0raLlAkD5dagHkiTh5s2bWofhNCLlBZHaCojXXi8vL8Vzvki5AGjbOhSySCAiIiIiosYJebkRERERERE1TsjRjUS7xECk05MitRUQr7283KjteLmR8YmUF0RqKyBee3m5UdvxcqMWiomJwaFDh7QOg4hayGKx4NNPP1XkoCFJEmJiYnD48GEFItMPi8WCrKwsrcNwqjlz5uDUqVNah0FELRQWFoZFixYplvPnzp0rXC4ICwvD4sWLW/VaIYsEUSpwIiPiEKhtJ1ra5xCoRPrFIVDbrrVDoAp5uZHN3r174ePjo3UYqrp8+TLi4+MBGL+9jm0VTXFxsSJfnF2V1WpFSEiIau9v9PUHqL8O9WDv3r2orq7WOgxVeXp6IjY2FgDw0ksvwdPTU+OI1FNWVoYVK1YA4LY1mlu3bmHJkiWqvf/GjRsVKTxcWUVFBSZOnNim9xC6SPDx8TH0l2YAsvYZvb1GbtvtmM1mw3/JVRPXnxiqq6sN/0XSsX2enp6G/iLp2DZuW2oJb29vwxcJSuDoRkREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEiGRQIREREREcmwSCAiIiIiIhkWCUREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQymhUJo0ePxsyZM7X6eCIicrK6eZ/HASIi16VJkXDlyhXs2rULnp6eWnw8ERE5Wd28z+MAEZFr06RIyMzMRE1NDRISErT4eCIicrK6eZ/HASIi16ZJkXDgwAEMGTIE4eHhWnw8ERE5Wd28z+MAEZFr06RIOHjwIJ5++mktPpqIiDRQN+/zOEBE5NqcXiSUlpbizJkzGD9+vLM/WlPTp09HdHQ0Xn75Zdn0AwcOIDo6GtHR0SgqKtIoOmWJ1FYAiIiIwFdffQVJkpCRkaF1OKqprKzEmjVr8MADDyA4OBi+vr7o06cPZs6cidOnT2sdni6Iug7r5n0RjgOi5AWAOd/oRNu+StJ7zle1SCgsLMTs2bMxYMAA+Pv7w83NDUFBQaiurkb79u3V/GiXUlVVhby8PADA4MGDZfOOHDkCAOjSpQvuvPNOp8emNJHa2q5dOyQlJSE7OxvR0dFah6OqoqIixMTEIDExEfn5+Rg/fjzmzJmDLl26IDU1FZGRkXj33Xe1DtOlibIOm5P3MzMz8eijjxryOCBSXgCY841OpO2rNCPkfA+13jgrKwuPPPIIrFZrvXlDhw5V62Nd0smTJ1FRUQEAGDRokGyebSeru/PplShtjYqKwvr16xEREYEjR47Ua6uRlJeXIy4uDrm5uYiIiEBGRgY6dOgAAEhKSkJycjLmz5+PhIQEdOzYESNGjNA4Ytcjyjpsbt7Py8vDlClTnBmaU4iUF2yY841ND9s3JycHzzzzDAoLCzF27FikpKTAx8dH05iMkvNVOZNQWVmJiRMnwmq1wt/fH2+//TaysrJw/PhxHD9+HJs3b1bjY11WTk4OAMDPzw99+vSxTy8vL0dBQQEA7XcypYjQ1vj4eHz++efo0aMHpk2bhscee0zrkFS1aNEi5ObmwmQyYcOGDfZEZzNv3jxYLBbU1NRg6tSpuHHjhkaRui4R1mFL8v5rr72GBx54QMNolSdaXrBhzjc2V9++169fx6hRo5Cbm4vS0lKkpaVh/vz5msVjY5Scr0qR8NFHH+Hs2bMAgMWLF+OFF16AxWJBeHg4wsPDERISosbHuqzc3FwAwMCBA+Hm9tMqP3bsGKqrqwHU/kphBCK0tWfPnti7dy/Cw8Oxdu1aSJKkdUiquXr1KpYuXQoAsFgsjR4MZsyYAaD29OqqVaucFp8eiLIORc/7IuUFR8z5xubq2zcrKwsXLlyQTdP6h2gj5XxVioQ9e/YAADw8PAx9Y1pzOF7PV/dUnW3nCwkJQbdu3Zwem9JEaeumTZswcuRInD9/XutQVLdjxw6UlZUBAEaNGtXociNHjrQfQLRO0K5GlHUoet4XKS/YMOcbmx62b01NTbOmOZORcr4q9yR89tlnAGorz4CAADU+wiUVFRVh9OjRjc5PTU1FampqvenFxcX1boJKT0936RuBRGprXZcuXdI6BKfZvXu3/e+mfi3y9/dH3759cerUKWRnZ6OkpATBwcHOCNHlibIORc37NkbPC8z5xqbX7RsTE4NOnTrh4sWL9mljx451ymc3xkg5X7EzCfPnz4fJZILJZMKpU6cA1F7LZptmMpmcerq5f//+jf4jouax/YoEAKGhoU0u6zj/+PHjqsWkN0Zeh66U95nzicQTEBCA9PR0DBw4EO3bt8fEiRPxl7/8RdOYjJTzFTuT0JzGGf3JmsHBwfjggw9k0xYuXIi8vDwMHjxYdjNNbm4u3nzzTQDA6tWr0bFjx3rv5cpEaquoJEmSjePcpUuXJpd3/OUoPz8fsbGxqsXWFFca6UKv67C5mPfFwZxvbHrevkOHDsXRo0ed+pmNMVrOV6xIWL58OZKTk7Ft2zYkJSUBADZu3IjIyEj7MoGBgUp93G2dPHmy0Xkmk0mVz/Tw8EDPnj1l086dOweg9no+x3m2B7AEBATocrxlkdoqqrKyMlRWVgKo3d7e3t5NLu/n52f/+8qVK6rG1hjbSBe2G9nS0tLg7++PZcuWaRKPHtdhS7hS3m8q58fFxTklBiNjzjc2bl9lGC3nK1Yk2E6ZrFmzBkDtF/HRo0cb8mE5zVVUVITS0lIAwD333CObZzs1369fP2eHpQqR2iqK69ev2/++XaKru4zja52psZEutCoS9LgOW4J5X1zM+cbG7ds6Rsv5io9uZLvjPTQ0VPgDxddff23/u+51sbadrO7Op1citZUa5jg8nlZccaSLlnCFddgazPviYc43Nj1t3+zsbERFRSEoKAiTJ09GeXm51iE1m6vnfEVHN6qpqcGxY8cA6P/hKUqw7WQhISGya/ZKS0vxww8/AHCdnaytRGqrKPz9/e1/25642RTHh8E4vtaZXG2kCz2uw5Zi3hcTc76x6WX7Xrt2DXFxcfYzyOvWrYOvry9SUlI0icdoOV/RIqGgoABWqxWAeAeLCxcu1OsQtgNn9+7d7Q8ZAuQ3+/n6+srmBQYGOvXejdYQqa0i8/PzQ7t27VBZWYmqqircvHkTXl5ejS7veKpUq+1qG+kiMTER3377LeLj4zUd6UKP67ClRM77omDONzY9b9+GLjHdsmWLZkWC0XK+okWC7ZQzIN7BYsGCBbL2O8rOzsbjjz/e4LznnntO9v+pU6di2rRpisenJJHaKjKTyYTevXvbf1EqKirCXXfd1ejyRUVF9r+1vFbVlUa60Os6bAmR874omPONjdtXOUbL+YpeDMWDBZGxDBgwwP53YWFhk8s6zo+IiFAtJr0x+jpk3icircTExNR7Fsu4ceM0iqaWkXK+KmcSevTogQ4dOij51i5v7dq1sv+npaVh1apVMJvN2L9/P9zd3QEA5eXlGDZsGKqrq7FgwYImn3DoqkRqq+hGjBiB999/H0DtL0qNjeF8/fp15OfnA6h9wqQzH5zo6oy+DkXO+6Jgzjc2PW/f9u3b2y8xLSwsxJgxY7Bo0SJNYzJSzlf0TILtFH9TvybNnz8fv/71r9GjRw+YzWYEBAQgIiICL774Ir777jslw9HUkSNHAACRkZH2HQyovc6vuroagHF+dROpraKJi4uD2WwGAOzcubPR5Xbt2mUfReiJJ55wSmyNcbWRLvS4Dlvidnn/8uXLWLduHcaNG4e+ffvCbDbDz88PgwcPxv/+7//a72cg/WDONza9bd8hQ4YgNzcXpaWl2LBhgz3fasVIOV+xIuGbb76xj6nbVOdZvnw5rl69ioceeggzZ85EQkICgoKCsHTpUvTv3x9ffPGFUiFpprq62v5Y7kGDBsnm2X51Cw4ORrdu3Zwem9JEaquIAgMD8fzzzwMADh061Oh1q6mpqQCAzp0749lnn3VafHXZRrqwHTDWrVuHuXPnahYPoL912BLNyftbtmzB5MmTcfDgQQwcOBAzZ87E73//e1y6dAmvvfYahgwZgkuXLjkxamoL5nxj4/ZtOyPlfMWKhOZel3r58mV8+eWXWLduHd566y0sX74cmZmZWL16Na5fv445c+YoFZJm8vPz7b9eRkVFyebl5OQAgOyJpHomUltF9corryAyMhKSJCEhIaHeF7rk5GQcOnQIbm5uWLt2raa/4jQ20oXW9LQOW6I5eb9Pnz748MMPUVRUhC1btuCtt97C6tWrUVBQgIcffhhff/01Fi5c6KyQqY2Y842N21cZRsn5it2T0NwiobEn0D3xxBNITEzEmTNnlApJM7ZTdT4+PggLC7NPr6iosN/x7kqn6tpCpLY6mjJlCgICAgAAQUFB9undu3fHiy++aP//nj17ZA+l0SOz2YydO3dizJgxyM7ORlhYGCZMmIDAwEBkZGQgMzMT3t7eWLlyJeLi4rQO1yUZdR02J+8/+OCDDU739vbG66+/jk8++QT79+9XJT5nEyEvMOcbd9sC4m5fpRkl5yteJHTu3BldunRp8es/+ugjAMDAgQOVCkkztnUREREBD4+fVvGxY8dQVVUFoP5pPL0Sqa2OXn31VfTs2bPe9NDQUCxZssT+/x9//FHXBwybrl274vDhw0hLS8OmTZuwadMmWK1WdOvWDdOnT8esWbPQt29frcO0j3RRXFxsn6b1SBc2elmHLdHWvO/p6QkAstyhZyLkBeZ8OSNtW0Dc7asGI+R8xTKzrfpsboW5fPlylJaW4vr168jLy8P+/fvRo0cPLFu2TKmQNLN06dIGp993333Izs52cjTqEqmtjpoa99io2rVrh8TERCQmJmodSqNccaQLR3pYhy3R0rxfl21Uld/85jeKxaQlEfICc76xibp91aL3nK9YkVBSUtKi5ZcvX47/+7//s/9/yJAheO+993D33XcrFRIRCcg20gWpr6V539HWrVuRlpaGHj16GOJeNCIio1F0CNSWOHv2LCRJwsWLF/Hxxx9DkiQMHjwYO3bs0CokIiJygk8++QQTJ05EQEAAtm/fjsDAQK1DIiKiOjQrEmw6duyIhx9+GHv37oWvry+eeuopXL16VeuwiIhIBenp6YiPj4e/vz/279/P65uJiFyU5kWCTWBgIO6//36Ulpbar3MlIiLjeP/99zF27FjccccdOHDgAAsEIiIX5jJFAgCcP38eQO2NHkREZBxr167Fk08+iTvvvBOZmZno37+/1iEREVETnFoknD59utFLiVauXIns7GyEhITg3nvvdWZYRESkorfffhvTpk3DXXfdhczMTA5QQUSkA04dnHr37t2YN28efv7zn6NXr17o1KkTLl68iM8++wwnT56E2WzGe++9Zx87m4iI9O3dd9/FSy+9BACIjY3F+vXr6y0TGBiIP/7xj06OjIiImuLUIuGhhx7CN998g0OHDmH79u0oLS2Fj48PQkND8dJLL2HWrFno3r27M0MiIiIVFRYW2v+2PRehrp/97GcsEoiIXIxTi4Tw8HCkpKQ48yOJiEhDSUlJSEpK0joMIiJqIZe6cZmIiIiIiLTHIoGIiIiIiGRYJBARERERkQyLBCIiIiIiknHqjcuu5saNG1qHoDrHNhq9vUZvX1OsVqvWIahK7fYZff0BYrTxdtzd3bUOQXWObbx165aGkajPsX3ctsaidvsqKipUfX9XoEQbTZIkSQrEoismk0nrEIiolcrKymA2m9v8PlarFX5+fgpEpD+ipf24uDitQyCiVtq6dSu8vb3b/D4VFRUYN26cAhHpz44dO1r1OiEvN7JYLFqHQEStYLFY4Ovrq8h7+fr6CpkLRGxzWFiY1iEQUSuEhYXBy8tLkffy8vISMhe0pc1CnkmQJAnl5eVah+E0tk0swhkUkdoKiNdeX19fRdsqWi4AlF+HeiBJEm7evKl1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yclBVFQUgoKCMGXKFNy4cUPrkADoZ/01xUOtN66srMTEiRNhtVrh7++PpKQk3HfffQgICAAAdOrUSa2PdjknT55ERUUFAGDQoEGyebakUjfZ6JUobS0vL0dcXBxyc3MRERGBjIwMdOjQAQCQlJSE5ORkzJ8/HwkJCejYsSNGjBihccRtExUVhfXr1yMiIgJHjhypt22paUZffy3J96+99ppWYapKtJwAGL9fN0SUY5xetu3169cxatQoXLhwAQCQlpYGf39/LFu2TNO49LL+bke1MwkfffQRzp49CwBYvHgxXnjhBVgsFoSHhyM8PBwhISFqfbTLycnJAQD4+fmhT58+9unl5eUoKCgAYIykAojT1kWLFiE3NxcmkwkbNmywfxmwmTdvHiwWC2pqajB16lSX+WWjNeLj4/H555+jR48emDZtGh577DGtQ9IVEdYf871YOQEQo183RIRjnJ62bVZWlr1AsNm8ebNG0dTS0/q7HdWKhD179gAAPDw8hL9BLTc3FwAwcOBAuLn9tMqPHTuG6upqALVVpxGI0NarV69i6dKlAACLxdLoAWHGjBkAai9BWLVqldPiU1rPnj2xd+9ehIeHY+3atfZLSKh5RFh/oud70XICIEa/bogIxzg9bduamppmTXMmPa2/21GtSPjss88A1O5ItlPOInK8frHu6SZbsgkJCUG3bt2cHpvSRGnrjh07UFZWBgAYNWpUo8uNHDnSfhDR+peNtti0aRNGjhyJ8+fPax2KLomw/kTP96LlBECMfl2XKMc4PW3bmJiYepevjx07VqNoaulp/d2OovckzJ8/H8nJybJpOTk5MJlM9v8HBwejuLhYyY91GUVFRRg9enSj81NTU5GamlpvenFxcb2bWtLT0136xieR2lrX7t277X839YuRv78/+vbti1OnTiE7OxslJSUIDg52RoiKunTpktYh6JpR15/o+d6RaDkBMG6/thH5GKenbRsQEID09HQkJibi22+/RXx8PP7yl79oGpOe1t/tKFokHD9+/LbLOOsJm/3793fK55B4bL8kAUBoaGiTy4aGhuLUqVMAaveP2NhYVWOj2i+qzzzzDAoLCzF27FikpKTAx8dH67AMx5XyPdB0zu/Vq5eqn82cQKSdoUOH4ujRo1qHYUiKFgnLly9HcnIytm3bhqSkJADAxo0bERkZaV8mMDBQyY90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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "def generate_logic_dict_from_boolean_node(boolean_node, k = 5, nnodes= 8):\n", + "partial_luts = [\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")], \n", + "]\n", + "partial_lut = partial_luts[3]\n", + "\n", + "\n", + "# generating a node with a required bias\n", + "\n", + "\n", + "\"\"\"\n", + "# Fill missing output values with the specified bias or with specified effective connectivity or randomly\n", + "generated_node = BooleanNode.from_output_list(partial_lut)\n", + "required_node_bias = 0.5 # Required bias of the node\n", + "verbose = True # Set to True to display the steps of the function\n", + "\n", + "if required_node_bias is not None: # If required node bias is specified, then fill missing output values with the specified bias.\n", + "\n", + " # Checking if required node bias is within the achievable bias range of the node.\n", + "\n", + " # Calculating max achievable bias\n", + " max_achievable_output = ['1' if output == '?' else output for output in generated_node.outputs]\n", + " max_achievable_bias = sum(map(int, max_achievable_output))/2**generated_node.k\n", + " min_achievable_bias = generated_node.bias(verbose=False)\n", + "\n", + " # Calculating the number of '1' required to achieve the required bias.\n", + " required_ones = int(required_node_bias * 2**generated_node.k)\n", + " current_ones = generated_node.outputs.count('1')\n", + "\n", + " # Checking if the required bias is achievable.\n", + " if required_node_bias > max_achievable_bias:\n", + " if verbose:\n", + " print(f\"Required Node Bias is greater than the maximum achievable bias ({max_achievable_bias}) of the node. Generating with the maximum achievable bias.\")\n", + " required_node_bias = max_achievable_bias\n", " \n", - " logic = {}\n", + " elif required_node_bias < min_achievable_bias:\n", + " min_achievable_bias = generated_node.bias(verbose=False)\n", + " if verbose:\n", + " print(f\"Required Node Bias is lower than the minimum achievable bias (bias = {min_achievable_bias}) of the node. Generating with the minimum achievable bias.\")\n", + " required_node_bias = min_achievable_bias\n", " \n", - " logic= { 0: {\n", - " 'name': boolean_node.name,\n", - " 'in': [input_node for input_node in boolean_node.inputs],\n", - " 'out': boolean_node.outputs\n", - " }\n", - " }\n", - " return logic\n", - "\n", - "logic = generate_logic_dict_from_boolean_node(generated_node)\n", - "print(logic)" + " # Fill the missing output values to achieve the required bias as closely as possible.\n", + " required_ones = int(required_node_bias * 2**generated_node.k) # recalculating in case the required bias was adjusted in the above steps.\n", + " ones_to_be_generated = required_ones - current_ones\n", + " number_of_missing_values = generated_node.outputs.count('?') \n", + "\n", + " missing_output_values = ['1'] * ones_to_be_generated + ['0'] * (number_of_missing_values - ones_to_be_generated) # creating a shuffled list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias.\n", + " random.shuffle(missing_output_values)\n", + " generated_node.outputs = [missing_output_values.pop() if output== '?' else output for output in generated_node.outputs]\n", + "\n", + " if verbose:\n", + " print(f\"Generated the node with a bias of {generated_node.bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {required_node_bias}.\")\n", + "\"\"\"\n", + "\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.5) \n", + "print(generated_node)\n", + "# plot_look_up_table(generated_node)\n", + "plot_schemata(generated_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating LUT with specified Effective connectivity\n", + "\n", + "The BooleanNode object calculates effective connectivity using the .effective_connectivity() function.\n", + "\n", + "```python\n", + "\n", + "generated_node.effective_connectivity()\n", + "\n", + "```\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generating a Look Up Table for a node with a specified effective connectivity. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated the node with the closest possible effective connectivity of 0.42447916666666674.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAwkAAAGZCAYAAADCYn3mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAABcSAAAXEgFnn9JSAABYa0lEQVR4nO3dfVRVdb4/8PcB5OEAAqOCFDomk0qKojDqHbitKWecbnrAMu/Nut6yNMkypyct67q4zboxWle9ws10jeYtZ9VSW1OoOeOaJUpQ0w1QMBXrht7GIcFUFA6iPOzfH+d3jmfzJA/78ft9v9ZyCecczvl8+H73Z/M5e5/vdiiKooCIiIiIiOj/CzA7ACIiIiIishY2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREFuN2u80OgYiIDGLVms8mgYj6Ze/evRg9ejQSExPNDsWSFi9ejObm5j7/XHl5OaZMmaJDRERE/cea3zMRaz6bBCIN1dbW4osvvsCJEydw7do1s8PRldvtxpkzZ3DmzBmzQ7GkrVu3YurUqaiqqur1z+Tl5SE9PR3/+7//q2NkRKQV1nzyErHmB5kdANlTc3Mz/vznP+Prr79GYGAgxo8fj7vuuguBgYE3/dmamhq8+uqrcDgc2Lp1qwHRDsz169exbds2FBYW4sqVKxg3bhyys7MxduxY32NOnTqF7OxsFBUV+W4LDw/HQw89hNzcXMTExJgROpns+PHj+OlPf4q8vDw8+uij3T6uvr4eCxcuREFBARRFQWhoqHFBEvUCaz5rPt2ccDVfIcvYvXu3cttttymjR482O5Qe7dy5U4mNjVUCAgJU/0aMGKH8/ve/v+nPf/XVV4rD4VACAgIMiHZgvv/+e2X8+PGdcg0NDVX++Mc/KoqiKH/729+U+Ph4JSAgQHE4HKp/AQEBytixY5Xa2lqTM+nZbbfd1ud/sbGxvhw73mf1OWyE3/72t8qgQYN8v6N//ud/VhobGzs9rqSkRPnxj3/smz+33367Ul5ebkLEZDTWfOthzWfN7y8Raz6bBAvZvn275Qvpjh07lMDAwC6Lozf2hx9+WGlqaur2Oey0w0hPT+8yT4fDofzoRz9S6urqlNmzZysOh0NxOp3KzJkzlYceeki58847leDgYF+eLpfL7FR65I3T+39v//mPu/9tdhhbI3h3Bt7fybhx45SKigrf/f/+7/+uDBo0yPd7e/jhh5WGhgYTIyYjseZbD2s+a/5AiFbz2SRYiNV3GLW1tUpUVJSvSNx3331Kfn6+sm7dOsXlcilBQUG++H/2s58ply9f7vJ57LLDKCgo8MWZmZmpfP7558rx48eVl156yXf7Cy+8oAQFBSn33HOPUldXp/r506dPKz/96U99j/2f//kfkzK5Of8dhhb/rD62Rrp06ZKSlZXl+92EhYUpb7zxhvLLX/7S9zsPDw9Xtm3bZnaoZDDWfGthzWfN14JINZ9NgoVYfYfx+uuvKw6HQwkMDFQ++OCDTvd/+eWXyvjx4305pKWlKRcvXuz0OLvsMB5++GHF4XAokyZNUtra2lT3PfTQQ77fxahRoxS3293lc9TV1Sk/+tGPlICAAOW5554zIux+iYiIUBwOhxIfH6/s3r27Vz/z/vvv22IcrWL9+vVKSEiI6l04h8OhJCcnKydOnDA7PDIBa761sOb3jDW/b0So+VzdSAPfffedJv9++OEHs1Pp0YEDB+BwOPDwww/jn/7pnzrdn5aWhi+++AIulwuKoqC8vBwzZszAxYsXTYh24EpLS+FwOLBo0SIEBKg3lSeeeAIAoCgKnnjiCTidzi6fY9iwYXjkkUegKAq++OIL3WPur2PHjuGuu+7CuXPn8I//+I944IEHUFdX1+PPOBwOg6ITwzPPPIP77rvP972iKIiOjsYnn3yCpKQkEyOjvmLN92DN74w1n7yEqPnm9Sfi6Os5fTc738+qXbr3g2t79uzp8XHt7e3KY4895sslJSVF+eGHH3z32+VdpcjISCUgIEApKirqdN+5c+d8ORQWFvb4PB999JHicDiUuLg4nSLVzltvvaVERkb6zr/t6XDoBx98YItxtIKzZ88qd955Z6fD+wEBAUpCQoJy+PBhs0OkPmDNV2PNV2PNJ1FqPo8kaETxnLo14H9WVl9fDwAYMWJEj49z/P9l7pYsWQJFUVBZWYm7777b8u+adeRd8zoqKqrTfbGxsb6vhwwZ0uPz3HrrrQCAy5cvaxidPp588kl89dVXuPvuu3Hp0iUsWrQIM2fO5LrYA7Bv3z6kpKSguLgYiqJg6tSp+Oqrr/Doo49CURT87W9/w4wZM/Daa69ZvgbQDaz5N7Dmq7Hmy02kms/rJGjAewhu+PDhGDNmTL+f59y5czh16pRWYWkuJCQEra2taGho6NXjN23ahMDAQLz11lv46quvMGPGDBw8eFDnKLUTExOD8+fP49KlS53u8z/serN1woOCgnr1OKsYOXIk/vznP2Pz5s1YsWIF/vznPyM5ORm/+c1vsHz5ch5y7qXW1lasXLkSGzZsgKIocDgceO655/Db3/4WQUFB2LZtG2bMmIEnn3wSjY2N+Ld/+zccOnQIv//97xEfH292+NQD1vyuseZ7sObLSciar8fhCdmMGTNGCQgIUO6+++4BPY/VP8SWlJSkBAQEKL/73e/69HNPP/20L6/k5GSlsLDQ0nl63XHHHUpAQECXH9hTlBunHBw/frzH5zl48KDicDiUUaNG6RGmrr777jtl5syZvlynT5/uy5eHnnv205/+1HeoeciQIcrevXu7fNzXX3+tTJ482fe7HDZsmLJ//36Do6W+YM3vGWs+a76MRKz5PN1IA6mpqVAUBUeOHDE7FF1NnDgRiqL0+Z2hvLw8PP3001AUBcePH8eDDz6oU4TaGj16NADg9OnTXd5//vx51NXVYdy4cT0+z4kTJwAAcXFx2gZogBEjRuBPf/oTtmzZgsjISHzxxReYMmUKcnJycP36dbPDs7TS0lIoioL09HQcPXoUs2bN6vJxt99+O/7yl7/4tpEffvgBLpfL4GipL1jze8aaz5ovIxFrPpsEDaSlpQHwnH/47bffmhyNfu68804AwJ49e9DU1NSnn924cSOWLVsGRVFw/vx5PcLTnPcPgbKysi7vHzJkCIYMGdJpFYyOCgsL4XA4cMcdd+gRpiEWLVqE48eP41e/+hWuX7+O3/zmN1i6dKnZYVmaw+HAyy+/jEOHDiEhIaHHxwYHB2Pjxo34wx/+gOjoaLS3txsUJfUHa/7Nseaz5stGxJrPJkED3h0G4OkkRXXPPfcAANxuN7Zt29bnn//P//xPLF++3PIf1PFKTU0FABw6dKjfz3HhwgV88sknAICf/exnWoRlmltvvRX79+/H7373OwwePBhut9vskCztj3/8I/793/+9T+clZ2Vl4ejRo/i7v/s7HSOjgWLN7x3WfNZ8mYhY8/nBZQ1MnjwZkyZNAoABvWOSkZGBd955R6uwNDd69Gj8y7/8C/72t7/1e8e4fv16BAcHY+fOnRpHp71/+Id/wF//+tcBPcef/vQnTJs2zfd8Injsscdwzz33YOPGjb7VQKizX/7yl/36uZEjR+Lw4cMaR0NaYs3vPdZ8+2PN7x0Ra75DsUuLT0REREREhuDpRkREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNgoPHjx2P8+PFmh2EImXIFmC/1DX9/cpBpnGXKFWC+1Dd2/f2xSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqDkVRFLODMFpGRgZKSkrMDoOI+ig9PR2ffvopHA7HgJ9LURT8/d//vXS1ID09HcXFxWaHYagVK1bg5MmTZodBRH2UlJSENWvWaFbzV65cKV0tSEpKwtq1a/v1s1I2CVpMNiIyR2NjI8LDwwf8PG63GxERERpEZD+ylX2Xy2V2CETUT7t27UJoaOiAn6e5uRnz5s3TICL72bNnT79+LkjjOGyltrZWkz82rKyurg6jR48GABw4cABhYWEmR6SfixcvIisrC4B8Y0sDI8N8cbvdiIuLMzsMU7333nua/LFhZfX19Vi8eDEA4IUXXkBwcLDJEemnsbERGzduBCDf2B44cABtbW0mR6SfwMBAzJw5U7fnl2G+NDc3Y8GCBQN6DqmbhPDwcOH/MPDPLywsTOgmwT832caWBkaG+UJAaGio8H8Y+OcXHBwsdJPgn5tsY9vW1iZ0k6A3GeaLFvjBZSIiIiIiUmGTQEREREREKmwSiIiIiIhIhU0CERERERGpsEkgIiIiIiIVNglERERERKTCJoGIiIiIiFTYJBARERERkQqbBCIiIiIiUmGTQEREREREKmwSiIiIiIhIhU0CERERERGpsEkgIiIiIiIVU5uEzMxMLFu2zMwQiIjIIB1rPvcBRETWZVqTcOnSJezbtw/BwcFmhUBERAbpWPO5DyAisjbTmoSioiK0t7dj4cKFZoVAREQG6VjzuQ8gIrI205qEQ4cOYerUqZgwYYJZIRARkUE61nzuA4iIrM20JuHw4cN47LHHzHp5IiIyUMeaz30AEZG1mdIk1NfX45tvvsH8+fPNeHkiIjJQx5rPfQARkfXp3iRUV1dj+fLlmDhxIiIjIxEQEICYmBi0tbVh8ODBer+86VpaWrB582bceeediI2NhdPpxJgxY7Bs2TJ8/fXXZoeni6VLlyItLQ0vvvii6vZDhw4hLS0NaWlpqKmpMSk6bck4vsnJyfjyyy+hKAoKCwvNDsdWZJgvvan5RUVFuO+++4TcB8gwxh2x5os9vqz5/Wf3+aJrk1BcXIyJEydi48aNOHbsGBobG6EoCgBg+vTper60JdTU1CAjIwPZ2dmoqqrC/PnzsWLFCsTHxyM/Px8pKSl49913zQ5TU62traisrAQATJkyRXXfkSNHAADx8fG45ZZbDI9Na7KN76BBg5CTk4PS0lKkpaWZHY7tyDBfelvzKysrsWjRIrPC1I0MY9wRa76448uaPzAizJcgvZ64paUFCxYsgNvtRmRkJHJycjBt2jRERUUBAIYNG6bXS1tCU1MTXC4XysvLkZycjMLCQgwZMgQAkJOTg9zcXKxatQoLFy7E0KFDce+995ocsTaOHz+O5uZmAMDkyZNV93l3GB13JHYk2/impqbinXfeQXJyMo4cOdJpbKlnMsyXvtT8V1991awwdSPDGHeFNV/M8bVTzS8rK8MTTzyB6upqzJ07F3l5eQgLCzM1JlHmi25HEj7++GOcOXMGALB27Vo899xzSE9Px4QJEzBhwgTExcXp9dKWsGbNGpSXl8PhcGD79u2+yeH18ssvIz09He3t7Vi8eDGuXr1qUqTaKisrAwBERERgzJgxvtubmppw6tQpAGLsMGQa36ysLPzlL3/ByJEjsWTJEtx///1mh2Q7MswX1nzxx7grrPkeIo2vnWp+Q0MDZs+ejfLyctTX12Pr1q1YtWqV2WEJM190axL2798PAAgKCpLuw2mXL1/GunXrAADp6endFsinn34agOeQ1KZNmwyLT0/l5eUAgEmTJiEg4Mb0qqioQFtbGwDPOxR2Jtv4jho1CgcOHMCECROwZcsW3+kj1DuyzBfWfPHHuCus+TeIMr52qvnFxcU4d+6c6rb333/fpGg8RJovujUJn3/+OQBP4fAebpbFnj170NjYCACYPXt2t4+bNWuWr6iaPam14H9uasdDk94dSVxcHBISEgyPTUuyje+OHTswa9YsnD171uxQbEmW+cKaL/4Yd8SarybK+Nqp5re3t/fqNiOJNF80/UzCqlWrkJubq7qtrKwMDofD931sbCxqa2u1fFnL+eSTT3xf9/QOSmRkJMaOHYuTJ0+itLQUdXV1iI2NNSLEAaupqUFmZma39+fn5yM/P7/T7bW1tZ0+AFVQUGCrD7XJML7+Lly4YHYItibyfGHN9xB5jL1Y8z1EHV9/dqr5GRkZGDZsGM6fP++7be7cuSZGJNZ80fRIwrFjx276GKOurjl+/Phu/+nN+84KACQmJvb4WP/7e/P7I/NxfKkvRJ4vrPkeIo8xcXytLCoqCgUFBZg0aRIGDx6MBQsW4I033jA1JpHmi6ZHEjZs2IDc3Fx8+OGHyMnJAQC89957SElJ8T0mOjpay5e0HEVRVGvfxsfH9/h4/3dTqqqqMGPGDN1i01JsbCx2796tuu21115DZWUlpkyZovrgUHl5OV5//XUAwNtvv42hQ4d2ei67kGV87cxKK12IPl9Y88UfYy/WfA9Rx9fOpk+fjqNHj5odBgDx5oumTYK3I9q8eTMAwOFwIDMz05QL5hw/frzb+/wPhWutsbERLS0tADwf4AsNDe3x8REREb6vL126pFtcWgsKCsKoUaNUt3333XcAPOem+t/nvfhKVFSU7ddalmV87cq70oX3g2xbt25FZGQk1q9fb0o8os8Xu9R8l8ul2+uKPsZerPlijy9pQ7T5ossHl70fWEpMTBTyipo9aWho8H19s8nR8TH+P2s3NTU1qK+vBwDccccdqvtOnjwJABg3bpzRYWlO1vG1C6utdCHLfGHN9xB5jDtize+aKONL/SPafNG8SWhvb0dFRQUAMdZG1pv/knF2duLECd/XHc8B9u4wOu5IZCDK+NqFFVe66As7zhfW/L6x4xh3hTW/a6KMr52UlpYiNTUVMTExePzxx9HU1GR2SL1m9fmi+RWXT506BbfbDUDOHUZkZKTva+9VKHvifwEN/5+1G+8OIy4uTnX+aX19Pb7//nsAYuwwZB1fu7DaShcyzBfWfPHHuCus+V0TZXzt4sqVK3C5XL4jyNu2bYPT6UReXp4p8Yg2XzRvEryHnQE5dxgREREYNGgQWlpa0NraimvXriEkJKTbx/sfXrLLB/zOnTvXafJ730kcMWKE76qrgPrT+k6nU3VfdHS0bXL2kmF87cy70kV2djZOnz6NrKwsU1e6kGG+sOaLP8as+WKPr511dYrpzp07TWsSRJsvbBI05nA4cPvtt/veZampqcFtt93W7eNramp8X9vl/M3Vq1erxtlfaWkpHnjggS7ve+qpp1TfL168GEuWLNE8Pj3JML52Z6WVLmSYL6z54o8xa77Y40vaEW2+aH4ylLeQjBw5EkOGDNH66W1h4sSJvq+rq6t7fKz//cnJybrFRNrh+FJfiD5fWPPFH2PZcXytKyMjA3Fxcarb5s2bZ1I0HiLNF82bBO87eD29o/Thhx/imWeewZ133ono6Gg4HA78/Oc/1zoU09x7772+r0tLS7t9XENDA6qqqgB4rsrXcaJb1ZYtW1BaWur79+STTwIAwsPD8cUXX/huLyoqQmBgIADPO1H+P1NaWmq7d5S8RB9f0pbo84U1X/wxZs0Xe3ztbPDgwSgoKMDkyZMRFRWFRx55BGvWrDE1JpHmi6ZNwrfffutbEq2nHcZvfvMb5OXloby8HAkJCVqGYAkulwvh4eEAgL1793b7uH379vlWXnnwwQcNiU0PR44cAQCkpKT4dhCA55zVtrY2AGKdhiDb+NqN1Va6EHm+sOZ7iDzGXWHN75oo42s3U6dORXl5Oerr67F9+3bfWJlFpPmiaZPQ23NT169fj1OnTuHKlSv44IMPtAzBEqKjo/Hss88CAEpKSro9lzM/Px8AMHz4cN87M3bT1tbmuwT55MmTVfd5846NjRXqDwOZxtduvCtdeHcY27Ztw8qVK02NSeT5wprvIfIYd8SaL/b40sCJNF9MaRLuuusujBkzxvLrww7ESy+9hJSUFCiKgoULF+LChQuq+3Nzc1FSUoKAgABs2bLF9M63v6qqqnzv1KampqruKysrA+B5t0k0soyv3XS30oXZRJ0vrPk3iDrGHbHmiz2+pA1R5oumqxt5dxjDhw9HfHy8lk9tO+Hh4di7dy/mzJmD0tJSJCUl4aGHHkJ0dDQKCwtRVFSE0NBQvPXWW3C5XGaH22/ew85hYWFISkry3d7c3Oz7dL9Ih529ZBlfr0WLFiEqKgoAEBMT47t9xIgReP75533f79+/X3WRJfIQdb6w5t8g6hh3xJov9vh6seYPjCjzRdMmwVs8RCwQ/XHrrbfis88+w9atW7Fjxw7s2LEDbrcbCQkJWLp0KZ555hmMHTvW7DAHxPtHQnJyMoKCbkyniooKtLa2Auh8SFoUMoyv1yuvvIJRo0Z1uj0xMRFvvvmm7/sffvjB1B2Gd6WL2tpa321mr3ThJeJ8Yc1XE3GMO2LNF3t8vexS861MhPmiaZNQV1en5dMJYdCgQcjOzkZ2drbZoehi3bp1Xd4+bdq0Hj/VLwrRx9erp3WercS70kV2djaqq6sxZ84c01e68CfafGHN70y0Me6INV/s8fWyS823OrvPF80vpkZEZCbvShdERETUf+J+ioyIiIiIiPqFTQIREREREamwSSAiIiIiIhU2CUREREREpGLKB5c/+ugjfPTRRwCA+vp6AJ4LtDz66KO+x2zfvt3wuIiISHus+URE9mNKk3D06FH893//t+q22tpa1W3cYRARiYE1n4jIfkw53SgnJweKovT4j4iIxMCaT0RkP/xMAhERERERqbBJICIiIiIiFTYJRERERESkwiaBiIiIiIhU2CQQEREREZGKKUugWoXb7TY7BN3553j16lUTI9Gff36yjS0NjAy/SxlyvJnm5mazQ9Cdf47Xr183MRL9+ecn29gGBgaaGIn+9M5PtvnSXw5FwrXnHA6H2SEQUT81NjYiPDx8wM/jdrsRERGhQUT2I1vZd7lcZodARP20a9cuhIaGDvh5mpubMW/ePA0isp89e/b06+ekPN0oPT3d7BCIqB/S09PhdDo1eS6n0yllLZAx56SkJLNDIKJ+SEpKQkhIiCbPFRISImUtGEjOUh5JUBQFTU1NZodhGO8Qy3AERaZcAfnydTqdmuYqWy0AtP8d2oGiKLh27ZrZYRhGprogU66AfPmGhIRoXvNlqgXAwH6HUjYJRERERETUPSlPNyIiIiIiou5JubqRbKcYyHR4UqZcAfny5elGA8fTjcQnU12QKVdAvnx5utHA8XSjPsrIyEBJSYnZYRBRH6Wnp+PTTz/VZKehKAoyMjLw2WefaRCZfaSnp6O4uNjsMAy1YsUKnDx50uwwiKiPkpKSsGbNGs1q/sqVK6WrBUlJSVi7dm2/flbKJkGWDpxIRFwCdeBkK/tcApXIvrgE6sD1dwlUKU838qqtrdXkjw0rq6urw+jRowGIn69/rgcOHEBYWJjJEenr4sWLyMrKAiB+vlevXsXMmTN1e37Rtw3A0xTFxcWZHYap3nvvPU3+2LCy+vp6LF68GID4+frn+sILLyA4ONjkiPTV2NiIjRs3AhA/3+vXr+PNN9/U7flF3zYAT1O0YMGCAT2H1E1CeHi48H8Y+Ocner7+uYWFhQn9RzMAVX4y5Ksn0bcN8ggNDRX+DwP//ETP1z+34OBgof9oBqDKT4Z89ST6tqEVrm5EREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpGJqk5CZmYlly5aZGQIRERmkY83nPoCIyLpMaxIuXbqEffv2ITg42KwQiIjIIB1rPvcBRETWZlqTUFRUhPb2dixcuNCsEIiIyCAdaz73AURE1mZak3Do0CFMnToVEyZMMCsEIiIySMeaz30AEZG1mdYkHD58GI899phZL09ERAbqWPO5DyAisjZTmoT6+np88803mD9/vhkvT0REBupY87kPICKyPt2bhOrqaixfvhwTJ05EZGQkAgICEBMTg7a2NgwePFjvlzddS0sLNm/ejDvvvBOxsbFwOp0YM2YMli1bhq+//trs8DQnW74AsHTpUqSlpeHFF19U3X7o0CGkpaUhLS0NNTU1JkWnPdny1ZIM20dvan5RURHuu+8+IfcBMoyxP9nyBeSrgbLlqyW7bx+6NgnFxcWYOHEiNm7ciGPHjqGxsRGKogAApk+frudLW0JNTQ0yMjKQnZ2NqqoqzJ8/HytWrEB8fDzy8/ORkpKCd9991+wwNSNbvgDQ2tqKyspKAMCUKVNU9x05cgQAEB8fj1tuucXw2PQgW75akmH76G3Nr6ysxKJFi8wKUzcyjLE/2fIF5KuBdsi3rKwMqampiImJwaJFi3D16lXTYvEnwvYRpNcTt7S0YMGCBXC73YiMjEROTg6mTZuGqKgoAMCwYcP0emlLaGpqgsvlQnl5OZKTk1FYWIghQ4YAAHJycpCbm4tVq1Zh4cKFGDp0KO69916TIx4Y2fL1On78OJqbmwEAkydPVt3nLaAdC6udyZavVmTYPvpS81999VWzwtSNDGPsT7Z8vWSrgVbPt6GhAbNnz8a5c+cAAFu3bkVkZCTWr19vWkyAONuHbkcSPv74Y5w5cwYAsHbtWjz33HNIT0/HhAkTMGHCBMTFxen10pawZs0alJeXw+FwYPv27b7J4fXyyy8jPT0d7e3tWLx4sWU63/6SLV+vsrIyAEBERATGjBnju72pqQmnTp0CINYOQ7Z8tSLD9sGaL/4Y+5MtXy/ZaqDV8y0uLvY1CF7vv/++SdHcIMr2oVuTsH//fgBAUFCQdB9Ou3z5MtatWwcASE9P73YDevrppwF4Dklt2rTJsPi0Jlu+/srLywEAkyZNQkDAjc2poqICbW1tAIDU1FRTYtODbPlqQZbtgzVf/DH2ki1ff7LVQKvn297e3qvbjCTS9qFbk/D5558D8Ews7+FmWezZsweNjY0AgNmzZ3f7uFmzZvk2Oit0vv0lW75e/udqdjwM6y2scXFxSEhIMDw2PciWr1Zk2T5Y88UfYy/Z8vWSrQbaId+MjIxOp6/PnTvXpGg8RNo+NP1MwqpVq5Cbm6u6raysDA6Hw/d9bGwsamtrtXxZy/nkk098X/fUYUdGRmLs2LE4efIkSktLUVdXh9jYWCNC1JQM+dbU1CAzM7Pb+/Pz85Gfn9/p9traWqSlpaluKygosPyH2mTLV08ibx+s+R4ij3FXZMhXthpo13yjoqJQUFCA7OxsnD59GllZWXjjjTcMee3uiLR9aHok4dixYzd9jFFX1xw/fny3//Tm7bwBIDExscfH+t/fm9+fFcmWL1mb1Va6EHn7YM33EHmMuyJbvmRt06dPx9GjR3H58mW8++67iIiIMDUekbYPTY8kbNiwAbm5ufjwww+Rk5MDAHjvvfeQkpLie0x0dLSWL2k5iqKo1r6Nj4/v8fH+3XZVVRVmzJihW2x6kCXf2NhY7N69W3Xba6+9hsrKSkyZMgWrVq3y3V5eXo7XX38dAPD2229j6NChnZ7L6uyar9VWuhB9+2DNF3+MO5IlX7vWwP6SLV+9iLZ9aNokeDuizZs3AwAcDgcyMzNNuWDO8ePHu73P/1C41hobG9HS0gLA8wG+0NDQHh/v3/FeunRJt7j0Iku+QUFBGDVqlOq27777DoDnXE3/+woLCwF4DoN2PAxrF3bNt7uVLsxqEkTfPuxS810ul26vK/oYdyRLvnatgf0lW756EW370OWDy94PtCQmJgp5Rc2eNDQ0+L6+2eTo+Bj/n7UL2fL1qqmpQX19PQDgjjvuUN138uRJAMC4ceOMDks3dsnXaitdyLJ9sOZ7iDzGXrLl62WXGqgVO+VbWlrqO8X08ccfR1NTk2mxiLZ9aH4xtfb2dlRUVAAQa61gvfgvKSYDUfI9ceKE7+uO5zx7C2jHwmpndsnXu9LF+fPnfbeZvdJFX9hx+2DN7xs7jvFAiJKvXWqgVuyS75UrV+ByuXxHkLdt2wan04m8vDyTI+sdq28fmkd36tQpuN1uAHLuMCIjI31fe69S2BP/D1X6/6xdyJavl7eAxsXFqc7HrK+vx/fffw/AGgVUK3bJ17vSxaRJkzB48GAsWLDA1JUuZNg+WPPFH2N/suXrZZcaqBW75NvVKaY7d+40KRrxtg/NjyR4DzsDcu4wIiIiMGjQILS0tKC1tRXXrl1DSEhIt4/3P7xkxw/4yZDvuXPnOm3s3ndOR4wY4bvKLKBencDpdKrui46OtkXOds/Xu9KFFciwfbDmiz/G/mTI1+41sK9ky1dPom0fbBI05nA4cPvtt/u68JqaGtx2223dPr6mpsb3tVXO7+sLGfJdvXq1al77Ky0txQMPPNDlfU899ZTq+8WLF2PJkiWax6c12fLVkwzbB2u++GPsT4Z8ZauBds43IyMDcXFxqmuxzJs3z9AY/Im2fWh+upF3oo0cORJDhgzR+ultYeLEib6vq6ure3ys//3Jycm6xaQn2fIl6gvRtw/WfPHHuCPZ8iXrGjx4MAoKCjB58mRERUXhkUcewZo1a0yNSaTtQ/MjCd7D/N29o3Tx4kV89NFH2L9/PyorK3H27Fk4HA6MGTMGc+fOxa9//WuEh4drHZah7r33XnzwwQcAPF14d+veNjQ0oKqqCoDnqnxxcXGGxagl0fPdsmWL6vutW7di06ZNCA8Px8GDBxEYGAgAaGpqwl133YW2tjasXr26x6tXWpnd8y0tLcWSJUtQXV2N+++/H3l5eXA6nabFI/r2wZov/hh3JHq+dq+BfWX3fKdOndrtkRAziLR9aHok4dtvv/UtmdXdDmPnzp14/PHHcfjwYUyaNAnLli3DP//zP+PChQt49dVXMXXqVFy4cEHLsAzncrl8O729e/d2+7h9+/b5lmd88MEHDYlND7Lle+TIEQBASkqKr3gCnnM429raAIh12oWd8vWudFFeXo76+nps27YNK1euNDUmkbcP1nwPkce4K7Lla6caqAXZ8tWaSNuHpk1Cb85NHTNmDP7whz+gpqYGO3fuxG9/+1u8/fbbOHXqFH71q1/hxIkTeO2117QMy3DR0dF49tlnAQAlJSXddrj5+fkAgOHDh+PJJ580LD6tyZRvW1ub75LrkydPVt3nzTs2NhYJCQmGx6YHu+VrtZUuALG3D9Z8D5HHuCsy5Wu3GjhQsuWrB5G2D8ObhLvvvhtz5sxBUJD6TKfQ0FD867/+KwDg4MGDWoZlipdeegkpKSlQFAULFy7s9E5Zbm4uSkpKEBAQgC1bttj+cLss+VZVVfku1JKamqq6r6ysDIDn3RdRyJavXkTdPljzbxB1jLsjS76y1UDZ8tWLKNuHpp9J8O4whg8fjvj4+D7/fHBwsCeoIM0/KmG48PBw7N27F3PmzEFpaSmSkpLw0EMPITo6GoWFhSgqKkJoaCjeeustuFwus8MdMFny9R6GDQsLQ1JSku/25uZm32oGIh2GtVu+VlvpwkvU7YM1/wZRx7g7suRrtxo4ULLlqxdRtg9NK7N3cvV3Ank/PPMP//APmsVkpltvvRWfffYZtm7dih07dmDHjh1wu91ISEjA0qVL8cwzz2Ds2LFmh6kZGfL1/lGUnJys+sOmoqICra2tADoforUzu+XrXekiOzsb1dXVmDNnjukrXXiJuH2w5quJOMY9kSFfu9XAgZItXz2JsH04FEVRzA4CAHbt2oV/+qd/wogRI1BRUaHrRSUcDgcAoLGx0bKHeLRSV1fn+8S86Pn65/rpp58iLCzM5Ij0dfHiRcycOROA+PlevXoVf//3fw9Au3nsdrsRERGh6XNamX++Vij7RtZ87zt1u3btQmhoqG6vYwX19fVYsGABAPHz9c911apVviNTompsbMSbb74JQPx8r1+/jtdffx2AdvO4ubnZd2RZ9G0DUOe7Z8+efj2H5tdJ6I8//elPWLBgAaKiovDRRx9Z8qpzRESkDdZ8IiLrM71JKCgoQFZWFiIjI3Hw4EEexiIiEhhrPhGRPZjaJHzwwQeYO3cufvSjH+HQoUPcWRARCYw1n4jIPkxrErZs2YKHH34Yt9xyC4qKijB+/HizQiEiIp2x5hMR2YspTcJ//Md/YMmSJbjttttQVFSEn/zkJ2aEQUREBmDNJyKyH8MXp3733XfxwgsvAABmzJiBd955p9NjoqOj8etf/9rgyIiISGus+URE9mR4k1BdXe372rtGdkc//vGPucMgIhIAaz4RkT0ZfrpRTk4OFEXp8d+ZM2eMDouIiHTAmk9EZE+mL4FKRERERETWwiaBiIiIiIhU2CQQEREREZEKmwQiIiIiIlIxfHUjK3G73WaHoDv/HEXP1z+/q1evmhiJMfxzFD1fvfMTfdsA5MjxZpqbm80OQXf+OYqer39+169fNzESY/jnKHq+eucn+rYBaJOjQ1EURYNYbMXhcJgdAhH1U2NjI8LDwwf8PG63GxERERpEZD+ylX2Xy2V2CETUT7t27UJoaOiAn6e5uRnz5s3TICL72bNnT79+TsrTjdLT080OgYj6IT09HU6nU5PncjqdUtYCGXNOSkoyOwQi6oekpCSEhIRo8lwhISFS1oKB5CzlkQRFUdDU1GR2GIbxDrEMR1BkyhWQL1+n06lprrLVAkD736EdKIqCa9eumR2GYWSqCzLlCsiXb0hIiOY1X6ZaAAzsdyhlk0BERERERN2T8nQjIiIiIiLqHpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVILMDsAMiqKgqanJ7DAMoygKAMDhcJgcif5kyhWQL1+n06lprrLVAkD736EdKIqCa9eumR2GYWSqCzLlCsiXb0hIiOY1X6ZaAAzsd+hQvDNOIhkZGSgpKTE7DCLqo/T0dHz66aea7DQURUFGRgY+++wzDSKzj/T0dBQXF5sdhqFWrFiBkydPmh0GEfVRUlIS1qxZo1nNX7lypXS1ICkpCWvXru3Xz0rZJMjSgROJqLGxEeHh4QN+HrfbjYiICA0ish/Zyr7L5TI7BCLqp127diE0NHTAz9Pc3Ix58+ZpEJH97Nmzp18/J+XpRl4HDhxAWFiY2WHo6uLFi8jKyjI7DMPJNra1tbWa/OFsVW63G3FxcWaHQTZ34MABtLW1mR2GroKDgzFjxgwAwAsvvIDg4GCTI9JPY2MjNm7cCED8XAG58r1+/TrefPNN3Z5fhloQGBiImTNnDug5pG4SwsLChP9DUvT8uiPb2IaHhwvdJBBpoa2tTfg/DPzzCw4OFvoPSf/cRM8VkC9fPclQC7TA1Y2IiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRimlNQmZmJpYtW2bWyxMRkYE61nzuA4iIrM2UJuHSpUvYt28fgoODzXh5IiIyUMeaz30AEZH1mdIkFBUVob29HQsXLjTj5YmIyEAdaz73AURE1mdKk3Do0CFMnToVEyZMMOPliYjIQB1rPvcBRETWZ0qTcPjwYTz22GNmvDQRERmsY83nPoCIyPoMbxLq6+vxzTffYP78+Ua/tKmWLl2KtLQ0vPjii6rbDx06hLS0NKSlpaGmpsak6LSXnJyML7/8EoqioLCw0OxwdCXL2La0tGDz5s248847ERsbC6fTiTFjxmDZsmX4+uuvzQ7PNmTaNoDONV+WfYBM4yxLDfRivh6i5qs1O9cCXZuE6upqLF++HBMnTkRkZCQCAgIQExODtrY2DB48WM+XtpTW1lZUVlYCAKZMmaK678iRIwCA+Ph43HLLLYbHprVBgwYhJycHpaWlSEtLMzsc3ckytjU1NcjIyEB2djaqqqowf/58rFixAvHx8cjPz0dKSgreffdds8O0NBm2jd7U/KKiItx3333C7gNkGGd/stRAL+Z7g4j5akmEWhCk1xMXFxfjnnvugdvt7nTf9OnT9XpZSzp+/Diam5sBAJMnT1bd593IOm58dpSamop33nkHycnJOHLkSKdcRSTD2DY1NcHlcqG8vBzJyckoLCzEkCFDAAA5OTnIzc3FqlWrsHDhQgwdOhT33nuvyRFbjwzbRm9rfmVlJRYtWmRkaIaRYZw7kqEG+mO+N1gl37KyMjzxxBOorq7G3LlzkZeXh7CwMFNjEqUW6NIktLS0YMGCBXC73YiMjEROTg6mTZuGqKgoAMCwYcP0eFnLKisrAwBERERgzJgxvtubmppw6tQpAOZvZAOVlZWF3bt3w+12Y8mSJThw4ABOnz5tdli6k2Fs16xZg/LycjgcDmzfvt3XIHi9/PLL2LdvH0pKSrB48WL87//+r+kF2kpk2Db6UvNfffVVs8LUlQzj3BUZaqA/5uthlXwbGhowe/ZsnDt3DgCwdetWREZGYv369abFJFIt0KVJ+Pjjj3HmzBkAwNq1a5Gdna3Hy9hGeXk5AGDSpEkICLhxhldFRQXa2toAeLpOOxs1ahQOHDiAJUuW4OzZs/jxj39sdkiGEH1sL1++jHXr1gEA0tPTu90ZPP300ygpKUFNTQ02bdqE5557zsgwLU2GbYM1X45x7oroNbAj5uthlXyLi4t9DYLX+++/b2qTIFIt0OUzCfv37wcABAUFCf/htJvxP5+v4+Em78YXFxeHhIQEw2PT0o4dOzBr1iycPXvW7FAMI8PY7tmzB42NjQCA2bNnd/u4WbNm+XYg77//viGx2YUM2wZrvhzj3JEMNdAf873BKvm2t7f36jYjiVQLdDmS8PnnnwPwdJ7ew80yqKmpQWZmZrf35+fnIz8/v9PttbW1nT7UUlBQYKsPAl24cMHsEHQl69h+8sknvq97ercoMjISY8eOxcmTJ1FaWoq6ujrExsYaEaLlib5tAPLWfH+ij7NsNZD5qlk134yMDAwbNgznz5/33TZ37lxDXrs7ItUCzZqEVatWITc3V3VbWVkZHA6H7/vY2FjU1tZq9ZI9Gj9+vCGvQyQy77tIAJCYmNjjYxMTE3Hy5EkAwLFjxzBjxgxdYyNz2anmjx492pAYiMhYUVFRKCgoQHZ2Nk6fPo2srCy88cYbZoclDM2ahGPHjt30MaJfXTM2Nha7d+9W3fbaa6+hsrISU6ZMwapVq3y3l5eX4/XXXwcAvP322xg6dGin5yLrkHFsFUVRXf8gPj6+x8f7v3NUVVVlWpNgxZUuRMSaLxfZaiDztU++06dPx9GjRw19TVlo1iRs2LABubm5+PDDD5GTkwMAeO+995CSkuJ7THR0tFYvd1PHjx/v9j7/d7q0FBQUhFGjRqlu++677wB4zufzv897QY2oqCjbrp8rExnHtrGxES0tLQA8+YeGhvb4+IiICN/Xly5d0jW27lhxpQtR2anmu1wuw+IQlWw1kPmKnS/1jmZNgvdUhM2bNwPw/CGemZkp7AVzeqOmpgb19fUAgDvuuEN1n/e0jHHjxhkdFmlAhrFtaGjwfX2zBqHjY/x/1khWXOlCVKz5cpOhBvpjvjeImC91TfPVjbyfeE9MTJR+Z3HixAnf1x3Pl/VuZB03PrIHjm1n/svjmcWKK12IjjVfTrLVQOZ7g9XyLS0tRWpqKmJiYvD444+jqanJ7JCEoenqRu3t7aioqAAg1sVE+su7kcXFxanO2auvr8f3338PwDobGfWNDGMbGRnp+9p7xc2eXL16tcufNZIVV7oQGWu+vGSogf6Yr4fV8r1y5QpcLpfvCPK2bdvgdDqRl5dncmRi0LRJOHXqFNxuNwD5dhjnzp3r9IeUd+c5YsQI34WGAPUH/pxOp+q+6OhoQ8/jpZuTdWwjIiIwaNAgtLS0oLW1FdeuXUNISEi3j/c/xcisPLnShbFkrvkyka0GMl/75NvVKaY7d+5kk6ARTZsE72FnQL4dxurVq1X5+ystLcUDDzzQ5X1PPfWU6vvFixdjyZIlmsdH/Sfr2DocDtx+++2+d5Rqampw2223dfv4mpoa39dmnqvKlS6MI3PNl4lsNZD53iBivtR7mp5EzB0GkVgmTpzo+7q6urrHx/rfn5ycrFtMZB2s+URkpoyMDMTFxalumzdvnknRiEeXIwkjR47EkCFDtHxqy9uyZYvq+61bt2LTpk0IDw/HwYMHERgYCABoamrCXXfdhba2NqxevbrHKxySNcg8tvfeey8++OADAJ53lLq79kFDQwOqqqoAeK7M3LFok5hkrvkyka0GMl/75Dt48GDfKabV1dWYM2cO1qxZY3ZYwtD0SIL3EH9P7yitWrUKv/zlLzFy5EiEh4cjKioKycnJeP755/HXv/5Vy3BMdeTIEQBASkqKbwMDPOf5tbW1AeA7b3Yl09i6XC6Eh4cDAPbu3dvt4/bt2+dbRejBBx80JLbucKUL47Dmy0mmGggwXy+r5jt16lSUl5ejvr4e27dv9+2zaOA0axK+/fZb35q6PU2eDRs24PLly/jFL36BZcuWYeHChYiJicG6deswfvx4fPHFF1qFZJq2tjZUVlYC8FyExJ/3nbfY2FgkJCQYHhsNjGxjGx0djWeffRYAUFJS0u15q/n5+QCA4cOH48knnzQsvo68K114dxjbtm3DypUrTYtHZKz5cpKtBjLfG0TMl3qm2elGvT039eLFi11emGnz5s3Izs7GihUrcPjwYa3CMkVVVZXv3cvU1FTVfWVlZQCguiop2YeMY/vSSy9h7969OHr0KBYuXIiDBw+qTi3Jzc1FSUkJAgICsGXLFlPfxeFKF8ZhzZeTbDWQ+d4gYr7UM8ObhO6u3Prggw8iOzsb33zzjVYhmcZ7qC4sLAxJSUm+25ubm30rxVjpUJ1WFi1ahKioKABATEyM7/YRI0bg+eef932/f/9+1YVa7ETGsQ0PD8fevXsxZ84clJaWIikpCQ899BCio6NRWFiIoqIihIaG4q233oLL5TI7XEsScdtgze9MxHHuSLYayHw9RM1XL6LUAs2bhOHDhyM+Pr7PP//xxx8DACZNmqRVSKbx/i6Sk5MRFHTjV1xRUYHW1lYAnQ/jieCVV17BqFGjOt2emJiIN9980/f9Dz/8YOmNoieyju2tt96Kzz77DFu3bsWOHTuwY8cOuN1uJCQkYOnSpXjmmWcwduxYs8P0rXRRW1vru80KK12IuG2w5ncm4jh3JFsNZL4eouarF1FqgWZNgrf77G2HuWHDBtTX16OhoQGVlZU4ePAgRo4cifXr12sVkmnWrVvX5e3Tpk1DaWmpwdEYp6c19EUh69gCwKBBg5CdnY3s7GyzQ+mWVVe6EHHbYM3vTMRx7ki2Gsh8PUTNVy+i1ALNmoS6uro+PX7Dhg34v//7P9/3U6dOxe9//3v85Cc/0SokIpKQd6UL0hdrPhGR2DRdArUvzpw5A0VRcP78efzxj3+EoiiYMmUK9uzZY1ZIRESkE9Z8IiJ7Ma1J8Bo6dCh+9atf4cCBA3A6nfiXf/kXXL582eywiIhIB6z5RET2YHqT4BUdHY2/+7u/Q319ve9cVyIiEhNrPhGRtVmmSQCAs2fPAvB8QJKIiMTGmk9EZF2GNglff/11t4eV33rrLZSWliIuLg4//elPjQyLiIh0wJpPRGRfmq1u1BuffPIJXn75ZfzsZz/D6NGjMWzYMJw/fx6ff/45jh8/jvDwcPz+979HcHCwkWEREZEOWPOJiOzL0CbhF7/4Bb799luUlJTgo48+Qn19PcLCwpCYmIgXXngBzzzzDEaMGGFkSEREpBPWfCIi+zK0SZgwYQLy8vKMfEkiIjIJaz4RkX1Z6oPLRERERERkPjYJRERERESkwiaBiIiIiIhU2CQQEREREZGKoR9ctpqrV6+aHYLuZMixKzLk7Z+j2+02MRL9iZ4fGSMwMNDsEHTnn+P169dNjER//vmJnisgV7565ydbLegvh6Ioigax2IrD4TA7BCLqp8bGRoSHhw/4edxuNyIiIjSIyH5kK/sul8vsEIion3bt2oXQ0NABP09zczPmzZunQUT2s2fPnn79nJSnG6Wnp5sdAhH1Q3p6OpxOpybP5XQ6pawFMuaclJRkdghE1A9JSUkICQnR5LlCQkKkrAUDyVnKIwmKoqCpqcnsMAzjHWIZjqDIlCsgX75Op1PTXGWrBYD2v0M7UBQF165dMzsMw8hUF2TKFZAv35CQEM1rvky1ABjY71DKJoGIiIiIiLon5elGRERERETUPSlXN5LtFAOZDk/KlCsgX7483WjgeLqR+GSqCzLlCsiXL083GjiebtRHGRkZKCkpMTsMIuqj9PR0fPrpp5rsNBRFQUZGBj777DMNIrOP9PR0FBcXmx2GoVasWIGTJ0+aHQYR9VFSUhLWrFmjWc1fuXKldLUgKSkJa9eu7dfPStkkyNKBE4mIS6AOnGxln0ugEtkXl0AduP4ugSrl6UZeBw4cQFhYmNlh6OrixYvIysoyOwzSmehz+erVq5g5c6bZYZDNvfDCCwgODjY7DF01NjZi48aNADx1oa2tzeSI9BMcHIwZM2YAkG9s33vvPU3+cLaq5uZmLFiwQLfnF33bADwXUxvoflPqJiEsLEzoP6wACJ8fecgwl4kGKjg4WPg/JP3za2trE/oPIf/cZBvb0NBQoZsEvYm+bWiFqxsREREREZEKmwQiIiIiIlJhk0BERERERCpsEoiIiIiISIVNAhERERERqbBJICIiIiIiFTYJRERERESkwiaBiIiIiIhU2CQQEREREZEKmwQiIiIiIlJhk0BERERERCpsEoiIiIiISIVNAhERERERqZjWJGRmZmLZsmVmvTwRERmoY83nPoCIyNpMaRIuXbqEffv2ITg42IyXJyIiA3Ws+dwHEBFZnylNQlFREdrb27Fw4UIzXp6IiAzUseZzH0BEZH2mNAmHDh3C1KlTMWHCBDNenoiIDNSx5nMfQERkfaY0CYcPH8Zjjz1mxksTEZHBOtZ87gOIiKzP8Cahvr4e33zzDebPn2/0SxMRkcE61nzuA4iI7EHXJqG6uhrLly/HxIkTERkZiYCAAMTExKCtrQ2DBw/W86UtZ+nSpUhLS8OLL76ouv3QoUNIS0tDWloaampqTIpOe8nJyfjyyy+hKAoKCwvNDkdXMuUKyDeXtSbyfOlNzS8qKsJ9990n/D5Atu1E5HndkSxj29LSgs2bN+POO+9EbGwsnE4nxowZg2XLluHrr782OzzbsPO2oVuTUFxcjIkTJ2Ljxo04duwYGhsboSgKAGD69Ol6vawltba2orKyEgAwZcoU1X1HjhwBAMTHx+OWW24xPDatDRo0CDk5OSgtLUVaWprZ4ehKply9ZJrLWhN9vvS25ldWVmLRokVmhWkImbYT0ed1R7KMbU1NDTIyMpCdnY2qqirMnz8fK1asQHx8PPLz85GSkoJ3333X7DABAGVlZUhNTUVMTAwWLVqEq1evmh0SADG2jSA9nrSlpQULFiyA2+1GZGQkcnJyMG3aNERFRQEAhg0bpsfLWtbx48fR3NwMAJg8ebLqPm9R6Vhs7Cg1NRXvvPMOkpOTceTIkU65ikSmXP3JMpe1Jvp86UvNf/XVV80K0zCybCeiz+uuyDC2TU1NcLlcKC8vR3JyMgoLCzFkyBAAQE5ODnJzc7Fq1SosXLgQQ4cOxb333mtarA0NDZg9ezbOnTsHANi6dSsiIyOxfv1602ICxNk2dDmS8PHHH+PMmTMAgLVr1+K5555Deno6JkyYgAkTJiAuLk6Pl7WssrIyAEBERATGjBnju72pqQmnTp0CYP+ikpWVhb/85S8YOXIklixZgvvvv9/skHQjU64dyTCXtSbDfGHNV5NhO5FhXndFhrFds2YNysvL4XA4sH37dl+D4PXyyy8jPT0d7e3tWLx4sanv3BcXF/saBK/333/fpGg8RNo2dGkS9u/fDwAICgrih9MAlJeXAwAmTZqEgIAbv/KKigq0tbUB8HSddjZq1CgcOHAAEyZMwJYtW3ynGYhIplw7kmEua02G+cKarybDdiLDvO6K6GN7+fJlrFu3DgCQnp7ebcPz9NNPA/CclrRp0ybD4uuovb29V7cZSaRtQ5cm4fPPPwfg2Yi8h5tl5X/+YsfDTd5iExcXh4SEBMNj09KOHTswa9YsnD171uxQdCdTrv5kmctak2G+sObfIMt2IsO87kiGsd2zZw8aGxsBALNnz+72cbNmzfI1SWa+c5+RkdHpFPa5c+eaFI2HSNuGZp9JWLVqFXJzc1W3lZWVweFw+L6PjY1FbW2tVi9pOTU1NcjMzOz2/vz8fOTn53e6vba2ttOHWgoKCmz1wacLFy6YHYJhZMhV5rmsNVHnC2u+3NuJqPPaS9ax/eSTT3xf93REJDIyEmPHjsXJkydRWlqKuro6xMbGGhGiSlRUFAoKCpCdnY3Tp08jKysLb7zxhuFx+BNp29CsSTh27NhNH2Pk1TXHjx9v2GsRkXWUlZXhiSeeQHV1NebOnYu8vDyEhYWZHZZw7FTzR48ebVgcRHbmPVICAImJiT0+NjExESdPngTgqQczZszQNbbuTJ8+HUePHjXltUWnWZOwYcMG5Obm4sMPP0ROTg4A4L333kNKSorvMdHR0Vq9nCXFxsZi9+7dqttee+01VFZWYsqUKVi1apXv9vLycrz++usAgLfffhtDhw7t9FxEZrHrXLbqShciYs2373ZCNyfj2CqKorr+QXx8fI+P9z86UlVVZVqTQPrRrEnwdpybN28GADgcDmRmZpp2wZzjx493e5//4XAtBQUFYdSoUarbvvvuOwCe8xf97/NeUCMqKsq26+eSuOw6l7tb6YJNgvbsVPNdLpcur2nX7YRuTsaxbWxsREtLCwBP/qGhoT0+PiIiwvf1pUuXdI2NzKH5B5e9H95JTEwU/oqaN1NTU4P6+noAwB133KG6z3uIbty4cUaHRdRndpnLVlzpQnSs+TfYZTuhvpNhbBsaGnxf36xB6PgY/581Wmlpqe9iao8//jiamppMi0U0ml5Mrb29HRUVFQDsv06wFk6cOOH7uuP5st6i0rHYEFmRXeayd6WL8+fP+24ze6ULkbHmq9llO6G+49h25r8ErFmuXLkCl8vlO4K8bds2OJ1O5OXlmRyZGDQd4VOnTsHtdgPgDgO4UVTi4uJU5yjW19fj+++/ByBfUSF7sstc9q50MWnSJAwePBgLFiwwfaULkbHmq9llO6G+k2FsIyMjfV97ryrdE/+LqPn/rJG6OsV0586dpsQiIk2PJHgPOwPy7TDOnTvXaaPyvsM2YsQI39VIAfWqIE6nU3VfdHS08B/2I2uz+1zmShfGYc2373ZC3ZN1bCMiIjBo0CC0tLSgtbUV165dQ0hISLeP9z/FyE55Uu+xSdDI6tWrVfn7Ky0txQMPPNDlfU899ZTq+8WLF2PJkiWax0fUW5zL1Fus+dxORCTr2DocDtx+++2+oyY1NTW47bbbun18TU2N72uzPo+RkZGBuLg41fVY5s2bZ0osItL0dCPvRjVy5EgMGTJEy6cmIiKLYc0nEsvEiRN9X1dXV/f4WP/7k5OTdYupJ4MHD0ZBQQEmT56MqKgoPPLII1izZo0psYhI0yMJ3kP8fXlH6c9//jNmzpwJRVGwfPlybNiwQcuQDLNlyxbV91u3bsWmTZsQHh6OgwcPIjAwEADQ1NSEu+66C21tbVi9enWPV3QkMoPd53JpaSmWLFmC6upq3H///cjLy4PT6TQ7LCGx5t9gt+2Euifz2N5777344IMPAHhqaXfXPmhoaEBVVRUAz5WZ4+LiDIuxo6lTp3Z75IcGRrMjCd9++61vebDe7jAuXryIRx99FOHh4VqFYRlHjhwBAKSkpPgKCuA5r7GtrQ2AfIfnyZ7sNJe9K12Ul5ejvr4e27Ztw8qVK80OS0is+Wp22k6ob2QaW5fL5ds+9+7d2+3j9u3b51te+sEHHzQkNjKeZk1Cf85Nzc7ORnNzs+rKhSJoa2vzXdp88uTJqvu8v6fY2FgkJCQYHhtRX9htLnOlC+Ow5t9gt+2Eek+2sY2Ojsazzz4LACgpKen2Hfr8/HwAwPDhw/Hkk08aFh8Zy7Qm4b//+7+xa9cuvPXWWze99LfdVFVV+S7mkZqaqrqvrKwMgOcdCSKr41ym7rDm38DtRFwyju1LL72ElJQUKIqChQsX4sKFC6r7c3NzUVJSgoCAAGzZskXII4PkodlnErw7jOHDh990B3DmzBk888wzmD9/Pv7xH/8R27dv1yoMS/AemgwLC0NSUpLv9ubmZt+qAaIcmvS3aNEiREVFAQBiYmJ8t48YMQLPP/+87/v9+/erLkxjR7Lkare5bNWVLkScL6z5N9htO9GKiPO6IxnHNjw8HHv37sWcOXNQWlqKpKQkPPTQQ4iOjkZhYSGKiooQGhqKt956Cy6Xy+xwLUmUbUOzJsG7Id1sY2lvb8eCBQsQERGB//qv/9Lq5S3Fu/NMTk5GUNCNX3FFRQVaW1sBdD5sKYJXXnkFo0aN6nR7YmIi3nzzTd/3P/zwg6U3it6QJVe7zWXvShfZ2dmorq7GnDlzLLHShYjzhTX/BrttJ1oRcV53JOvY3nrrrfjss8+wdetW7NixAzt27IDb7UZCQgKWLl2KZ555BmPHjjU7TMsSZdvQrEmoq6vr1eNyc3NRXFyM/fv3q7orkaxbt67L26dNm4bS0lKDozFOT+spi0aWXO04l6240oWI84U1/wY7bidaEHFedyTr2ALAoEGDkJ2djezsbLNDsR1Rtg1Nr5NwM2VlZfi3f/s3ZGdn45577jHypYmIyGCs+URE9mVYk9Da2oqHH34YI0eOVB1qISIi8bDmExHZm2FNQmNjI06dOoVvv/0WERERcDgcvn8LFy4EAPznf/4nHA4Hfv7znxsVFhER6YA1n4jI3jS94nJPQkJC8Pjjj3d53zfffIOioiKMHz8e06dP54dhiIhsjjWfiMjeDGsSwsLC8Lvf/a7L+7Zv346ioiL84he/wIYNG4wKiYiIdMKaT0Rkb4Z+cJmIiIiIiKyPTQIREREREakYdrpRTx599FE8+uijZodBREQGYM0nIrI+HkkgIiIiIiIVNglERERERKTCJoGIiIiIiFTYJBARERERkYolPrhslqtXr5odgu5kyJHEH2fR8yNjXL9+3ewQdOefY2BgoImR6M8/P9nGtrm52cRI9Kd3fqJvG4A2OToURVE0iMVWHA6H2SEQUT81NjYiPDx8wM/jdrsRERGhQUT2I1vZd7lcZodARP20a9cuhIaGDvh5mpubMW/ePA0isp89e/b06+ekPN0oPT3d7BCIqB/S09PhdDo1eS6n0yllLZAx56SkJLNDIKJ+SEpKQkhIiCbPFRISImUtGEjOUh5JUBQFTU1NZodhGO8Qy3AERaZcAfnydTqdmuYqWy0AtP8d2oGiKLh27ZrZYRhGprogU66AfPmGhIRoXvNlqgXAwH6HUjYJRERERETUPSlPNyIiIiIiou5JubqRbKcYyHR4UqZcAfny5elGA8fTjcQnU12QKVdAvnx5utHA8XSjPsrIyEBJSYnZYRBRH6Wnp+PTTz/VZKehKAoyMjLw2WefaRCZfaSnp6O4uNjsMAy1YsUKnDx50uwwiKiPkpKSsGbNGs1q/sqVK6WrBUlJSVi7dm2/flbKJkGWDpxIRFwCdeBkK/tcApXIvrgE6sD1dwlUKU83ktWBAwcQFhZmdhi6uXjxIrKysgCInysgV75Xr17FzJkzzQ6DbO6FF15AcHCw2WHoqrGxERs3bgTgqQttbW0mR6Sf4OBgzJgxA4D4uQLqfEWfy9evX8ebb76p2/PLMF8CAwMHvN9kkyCRsLAwof+Q9M9N9FwB+fIlGqjg4GCh/7ACoMqvra1N6D+E/HMTPVdAna8Mc1lPMswXLXB1IyIiIiIiUmGTQEREREREKmwSiIiIiIhIhU0CERERERGpsEkgIiIiIiIVNglERERERKTCJoGIiIiIiFTYJBARERERkQqbBCIiIiIiUmGTQEREREREKmwSiIiIiIhIhU0CERERERGpsEkgIiIiIiIVNglERERERKRiapOQmZmJZcuWmRkCEREZpGPN5z6AiMi6TGsSLl26hH379iE4ONisEIiIyCAdaz73AURE1mZak1BUVIT29nYsXLjQrBCIiMggHWs+9wFERNZmWpNw6NAhTJ06FRMmTDArBCIiMkjHms99ABGRtZnWJBw+fBiPPfaYWS9PREQG6ljzuQ8gIrI2U5qE+vp6fPPNN5g/f74ZL09ERAbqWPO5DyAisj7dm4Tq6mosX74cEydORGRkJAICAhATE4O2tjYMHjxY75e3jOTkZHz55ZdQFAWFhYVmh6OrpUuXIi0tDS+++KLq9kOHDiEtLQ1paWmoqakxKTrtMV8PUfPVmui1oDc1v6ioCPfdd5/Q+wDZthPR57U/mXIF5JvLWrPzfAnS88mLi4txzz33wO12d7pv+vTper60ZQwaNAivvPIKXn75ZSlW8WhtbUVlZSUAYMqUKar7jhw5AgCIj4/HLbfcYnhsemC+N4iYr5ZkqAW9rfmVlZVYtGiRkaEZSqbtRIZ57SVTrl52mMtlZWV44oknUF1djblz5yIvLw9hYWGmxeMlwnzRrUloaWnBggUL4Ha7ERkZiZycHEybNg1RUVEAgGHDhun10paRmpqKd955B8nJyThy5AgmT55sdki6O378OJqbmwGgU77egtKx0NgZ871BxHy1IkMt6EvNf/XVV80K0xCybCcyzGsvmXL1Z/W53NDQgNmzZ+PcuXMAgK1btyIyMhLr1683LSZAnPmiW5Pw8ccf48yZMwCAtWvXIjs7W6+XsqSsrCzs3r0bbrcbS5YswYEDB3D69Gmzw9JdWVkZACAiIgJjxozx3d7U1IRTp04BEGPn6MV8PUTNVwuy1ALZa74/GbYTWeY1IFeuHVl9LhcXF/saBK/333/f1CZBpPmi22cS9u/fDwAICgqS8sNpo0aNwoEDBzBhwgRs2bIFiqKYHZIhysvLAQCTJk1CQMCN6VVRUYG2tjYAng5bFMzXQ9R8tSBLLZC95vuTYTuRZV4DcuXakdXncnt7e69uM5JI80W3JuHzzz8H4JlY3sPNMtmxYwdmzZqFs2fPmh2KYfzPXex4aM1baOLi4pCQkGB4bHpgvjeImK9WZKkFstd8L1m2E1nmNSBXrv7sMJczMjI6nb4+d+5ck6LxEGm+aHq60apVq5Cbm6u6raysDA6Hw/d9bGwsamtrtXzZLo0fP1731+jJhQsXTH19vdXU1CAzM7Pb+/Pz85Gfn9/p9traWqSlpaluKygosPwH+Jivmmj56knkWmCXmj969GhdXlPm7UTked2RDLnadS5HRUWhoKAA2dnZOH36NLKysvDGG28Y8trdEWm+aHok4dixYzd9DK+uSUR6KisrQ2pqKmJiYrBo0SJcvXrV7JCExZpPRGabPn06jh49isuXL+Pdd99FRESE2SEJQ9MjCRs2bEBubi4+/PBD5OTkAADee+89pKSk+B4THR2t5Ut26/jx493e5/8uF/VPbGwsdu/erbrttddeQ2VlJaZMmYJVq1b5bi8vL8frr78OAHj77bcxdOjQTs9ldczXHvladaULUdml5rtcLl1e067bCVFHnMvUFU2bhMTERADA5s2bAXj+GM/MzBT6gjmyCgoKwqhRo1S3fffddwA85y763+e9eEhUVFSnw5J2wXztka8VV7oQmew1367bCVFHnMvUFV0+uOz9QEtiYqI0OwvZ1dTUoL6+HgBwxx13qO47efIkAGDcuHFGh6Ub5nuDlfK14koXMmDN97DLdkJ0M3aay6Wlpb5TTB9//HE0NTWZHZIwNL9OQnt7OyoqKgDYfx1o6r0TJ074vu74AUJvQelYaOyM+d5gpXy9K12cP3/ed5vZK12IjjX/BrtsJ0Q3Y5e5fOXKFbhcLt8R5G3btsHpdCIvL8/kyMSg+ZGEU6dOwe12A+AOQybeghIXF6c6P7G+vh7ff/89AGsUFK0wXw+r5etd6WLSpEkYPHgwFixYYPpKF6Jjzb/BLtsJ0c3YZS53dYrpzp07TYpGPJofSfAedga4wxDVuXPnfJdp9/K+kzhixAjfVVcB9eonTqdTdV90dLRhH2ocCOZrr3y9K12QMWSt+XbfToi8OJepO2wSqM9Wr16tGmd/paWleOCBB7q876mnnlJ9v3jxYixZskTz+LTGfG8QMV8aGFlrPrcTEoWd53JGRgbi4uJU12KZN2+eoTGITPPTjbwTbeTIkRgyZIjWT09ERBbCmk9EZhk8eDAKCgowefJkREVF4ZFHHsGaNWvMDksYmh9J8B7m7+kdpZ///Oc4fPhwt/efPHnSMp+ap862bNmi+n7r1q3YtGkTwsPDcfDgQQQGBgIAmpqacNddd6GtrQ2rV6/u8WqOVsZ87ZVvaWkplixZgurqatx///3Iy8uD0+k0OyxhyVrz7b6dEHnZfS5PnTq12yMhNDCaNgnffvutb8ms3hx2Xr58eZfnr3W8MAdZ25EjRwAAKSkpvmICeM5pbGtrAyDWaQjM18OK+XKlC2Ox5t9gp+2EqCecy+SlaZPQ13NTf/3rX3e6eAfZS1tbGyorKwF4LrjizzsfYmNjkZCQYHhsemC+N1gx3+5WumCToA/WfA+7bSdE3eFcJn+afiZB1g+wyayqqsp34ZLU1FTVfWVlZQA870aIgvneIGK+1Des+R7cTkgUnMvkT5cjCcOHD0d8fPxNH79//35cuXIFgYGB+MlPfoK7775bqKt1Llq0CFFRUQCAmJgY3+0jRozA888/7/t+//79qguX2In3sGRYWBiSkpJ8tzc3N/tyEumPB+brYdV8rbrShai1gDXfw27biVZEndddkSVXWeey1kSZL5o2Cd7J1dsJtHTpUtX3kZGRyM3N7bSsll298sorXR5aT0xMxJtvvun7/ocffrD0JOmJ94+E5ORkBAXdmE4VFRVobW0F0PmQpZ0xXw+r5utd6SI7OxvV1dWYM2eOJVa6ELUWsOZ72G070Yqo87orsuQq61zWmijzRdMmoa6urlePy8zMxPPPP4/Jkydj6NCh+Otf/4oPP/wQr7/+Op5++mkMGjQITzzxhJahmeK2224zOwTdrVu3rsvbp02bhtLSUoOj0R/z9bByvlZc6ULUWsCa72HH7UQLos7rrsiSq6xzWWuizBfNr5PQG8899xxcLhcSEhIQGhqK22+/HS+99BL+8Ic/APB0YN5P0BMRkb2x5hMR2Y8pTUJ3ZsyYgTFjxlj+8AsREQ0caz4RkXVZqkkAgB/96EcAALfbbXIkRESkN9Z8IiJrslST0NjYiK+++goOh0OY87mIiKhrrPlERNZleJNw+vRpXLhwodPtDQ0NePzxx9HY2IiZM2ciLi7O6NCIiEhjrPlERPak6epGvXH48GEsWbIEGRkZGD16NIYOHYqzZ8/iwIEDqKurw09+8hP87ne/MzosIiLSAWs+EZE9Gd4kpKamYv78+SgrK8PRo0dx5coVhIeHY9y4cXj22Wfx9NNPIyIiwuiwiIhIB6z5RET2ZHiTkJycjO3btxv9skREZALWfCIie7LUB5eJiIiIiMh8bBKIiIiIiEiFTQIREREREamwSSAiIiIiIhXDP7hM5rl69arZIejKPz/RcwXkylf0/MgY169fNzsE3fnnGBgYaGIk+vPPT/RcAXWOos9lvfOTbb70l0NRFEWDWGzF4XCYHQIR9VNjYyPCw8MH/Dxut1vapTdlK/sul8vsEIion3bt2oXQ0NABP09zczPmzZunQUT2s2fPnn79nJSnG6Wnp5sdAhH1Q3p6OpxOpybP5XQ6pawFMuaclJRkdghE1A9JSUkICQnR5LlCQkKkrAUDyVnKIwlERERERNQ9KY8kEBERERFR99gkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREamwSSAiIiIiIhU2CUREREREpMImgYiIiIiIVNgkEBERERGRCpsEIiIiIiJSYZNAREREREQqbBKIiIiIiEiFTQIREREREan8P1fLVE74ngaMAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "partial_luts = [\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"1\"), (\"01-1\", \"1\")],\n", + " \n", + "]\n", + "partial_lut = partial_luts[0]\n", + "\n", + "\"\"\"\n", + "# Inner workings of the from_partial_lut() function under BooleanNode class\n", + "\n", + "required_effective_connectivity = .7\n", + "\n", + "generated_outputs = generated_node.outputs.copy()\n", + "missing_output_indices = [i for i, x in enumerate(generated_outputs) if x == '?']\n", + "print(f\"Missing output indices = {missing_output_indices}.\")\n", + "\n", + "missing_output_count = generated_outputs.count('?')\n", + "print(f\"No. of '?' in output = {missing_output_count}.\")\n", + "permutations = list(product(*[('0', '1')] * (missing_output_count)))\n", + "print(permutations) \n", + "generated_node_permutations = [None] * len(permutations)\n", + "\n", + "for count, permutation in enumerate(permutations):\n", + " for i, index in enumerate(missing_output_indices):\n", + " generated_outputs[index] = permutation[i]\n", + " generated_node_permutations[count] = BooleanNode.from_output_list(generated_outputs)\n", + "\n", + "print(f\"Total output permutations generated = {len(generated_node_permutations)}.\")\n", + "\n", + "permutation_effective_connectivity = [x.effective_connectivity() for x in generated_node_permutations]\n", + "print(permutation_effective_connectivity)\n", + "closest_value = min(permutation_effective_connectivity, key=lambda x: abs(x - required_effective_connectivity))\n", + "print(f\"Closest value to required effective connectivity: {closest_value}\")\n", + "\n", + "closest_index = permutation_effective_connectivity.index(closest_value)\n", + "generated_node_permutations[closest_index].look_up_table()\n", + "\n", + "\"\"\"\n", + "\n", + "# Incorporating the above functions into the from_partial_lut() under BooleanNode class\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut, required_effective_connectivity=0.45)\n", + "\n", + "# plot_look_up_table(generated_node)\n", + "plot_schemata(generated_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Note: \n", + "\n", + "from_partial_lut() will throw an error if there are mutliple kwargs inputted. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```python\n", + "generated_node = BooleanNode.from_partial_lut(partial_lut, fill_missing_output_randomly= True, required_effective_connectivity=0.7, required_node_bias=0.5)\n", + "\n", + "ValueError: Only one of required_effective_connectvity, required_node_bias and fill_missing_output_randomly can be True. Please set the rest to False.\n", + "```" ] } ], diff --git a/tutorials/temp.ipynb b/tutorials/temp.ipynb index 6712de8..8528e09 100644 --- a/tutorials/temp.ipynb +++ b/tutorials/temp.ipynb @@ -714,6 +714,56 @@ "bn = BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], name=\"EG\")\n", "print(bn)" ] + }, + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "source": [ + "## Instantiating a Boolean Network \n", + "\n", + "The Boolean Network is created using the BooleanNetwork.from_dict() function which takes a Logic Dictionary as input. \n", + "\n", + "The logic dict is in the following format:\n", + "\n", + "```python\n", + "logic = {\n", + " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", + " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", + " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", + " }\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "\n", + "def generate_logic_dict_from_boolean_node(boolean_node, k = 5, nnodes= 8):\n", + " \n", + " logic = {}\n", + " \n", + " logic= { 0: {\n", + " 'name': boolean_node.name,\n", + " 'in': [input_node for input_node in boolean_node.inputs],\n", + " 'out': boolean_node.outputs\n", + " }\n", + " }\n", + " return logic\n", + "\n", + "logic = generate_logic_dict_from_boolean_node(generated_node)\n", + "print(logic)" + ] } ], "metadata": { From 37f4439affe1eedef3960632f4c347a221000ea3 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 17 Jun 2024 18:27:27 -0400 Subject: [PATCH 08/14] updated from_partial_lut --- cana/datasets/bio.py | 12 - cana/datasets/tempy.txt | 62 --- tests/test_boolean_node.py | 2 +- tutorials/temp.ipynb | 790 ------------------------------------- 4 files changed, 1 insertion(+), 865 deletions(-) delete mode 100644 cana/datasets/tempy.txt delete mode 100644 tutorials/temp.ipynb diff --git a/cana/datasets/bio.py b/cana/datasets/bio.py index f7c1863..bfe8a42 100644 --- a/cana/datasets/bio.py +++ b/cana/datasets/bio.py @@ -21,18 +21,6 @@ _path = os.path.dirname(os.path.realpath(__file__)) """ Make sure we know what the current directory is """ -def TEMPY(): - """ - A temp txt file to test the loader. - - Returns: - (BooleanNetwork) - """ - return BooleanNetwork.from_file( - _path + "/tempy.txt", - name="Tempy", - keep_constants=True, - ) def PARTIAL_LUTS_DEMO(): """ diff --git a/cana/datasets/tempy.txt b/cana/datasets/tempy.txt deleted file mode 100644 index 0c80d0f..0000000 --- a/cana/datasets/tempy.txt +++ /dev/null @@ -1,62 +0,0 @@ -# total number of nodes -.v 7 - -# labels of nodes and names of corresponding components -.l 1 One -.l 2 Two -.l 3 Three -.l 4 Four -.l 5 Five -.l 6 Six -.l 7 Seven - -# 1 = One -.n 1 0 -1 - -# 2 = Two -.n 2 0 -1 - -# 3 = Three -.n 3 0 -1 - -# 4 = Four -.n 4 0 -1 - -# 5 = Five -.n 5 3 3 4 2 -000 1 -0-0 0 -1-0 1 -111 1 - -# 6 = Six -.n 6 2 1 2 -00 0 -01 1 -11 1 - -# 7 = Seven -.n 7 6 1 2 3 4 5 6 -0--000 0 ---0--- 0 -1--111 0 --1---- 0 --01-10 1 --0110- 1 -001-1- 1 --01-01 1 --010-1 1 -101-0- 1 -101--0 1 -001--1 1 -001--1 1 -0011-- 1 -1010-- 1 --011-0 1 --0101- 1 - -.e end of file \ No newline at end of file diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index 6064698..d4a8768 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -4,7 +4,7 @@ # These tests were manually calculated by Luis M. Rocha and implemented by Rion B. Correia. # from cana.datasets.bools import CONTRADICTION, AND, OR, XOR, COPYx1, RULE90, RULE110 -from cana.utils import isclose +from cana.utils import isclose, fill_out_lut from cana.boolean_node import BooleanNode diff --git a/tutorials/temp.ipynb b/tutorials/temp.ipynb deleted file mode 100644 index 8528e09..0000000 --- a/tutorials/temp.ipynb +++ /dev/null @@ -1,790 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from matplotlib.text import Text\n", - "from matplotlib import pyplot as plt\n", - "from matplotlib.collections import PatchCollection\n", - "from matplotlib.patches import Rectangle\n", - "from IPython.display import display" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from cana.datasets.bio import TEMPY\n", - "from cana.datasets.bio import (\n", - " THALIANA,\n", - " DROSOPHILA,\n", - " BUDDING_YEAST,\n", - " MARQUESPITA,\n", - " LEUKEMIA,\n", - " BREAST_CANCER,\n", - ")\n", - "from cana.boolean_node import BooleanNode\n", - "from cana.drawing.schema_vis import plot_schemata\n", - "from cana.drawing.plot_look_up_table import plot_look_up_table\n", - "from cana.utils import fill_out_lut\n", - "\n", - "from cana.boolean_node import BooleanNode\n", - "from cana.boolean_network import BooleanNetwork" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# modified the BooleanNetwork.from_string_cnet function that is called in the BooleanNetwork.from_file function to check for duplicate values in the inputs and outputs of the nodes.\n", - "# this will print a warning message if there are duplicate values in the inputs and outputs of the nodes.\n", - "# This also generates a lookup table data for nodes with k>1\n", - "\n", - "# plot_schemata(tempy.nodes[4])\n", - "# plot_look_up_table(tempy.nodes[4])" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Entry clash in node 5 for {'000'} i.e. State number: 0\n" - ] - } - ], - "source": [ - "thaliana = THALIANA()\n", - "drosophila = DROSOPHILA()\n", - "budding_yeast = BUDDING_YEAST()\n", - "marquespita = MARQUESPITA()\n", - "leukemia = LEUKEMIA()\n", - "breast_cancer = BREAST_CANCER()\n", - "tempy = TEMPY()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# plot_schemata(node)\n", - "# print(node.schemata_look_up_table(type=\"pi\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " In: Out:\n", - "0 000000 0\n", - "1 000001 0\n", - "2 000010 0\n", - "3 000011 0\n", - "4 000100 0\n", - ".. ... ...\n", - "59 111011 0\n", - "60 111100 0\n", - "61 111101 0\n", - "62 111110 0\n", - "63 111111 0\n", - "\n", - "[64 rows x 2 columns]\n", - " Input Output\n", - "0 0##000 0\n", - "1 #1#### 0\n", - "2 1##111 0\n", - "3 ##0### 0\n", - "4 1010## 1\n", - "5 #01#10 1\n", - "6 0011## 1\n", - "7 #0101# 1\n", - "8 001#1# 1\n", - "9 #011#0 1\n", - "10 001##1 1\n", - "11 101##0 1\n", - "12 #01#01 1\n", - "13 #010#1 1\n", - "14 #0110# 1\n", - "15 101#0# 1\n", - "\n" - ] - } - ], - "source": [ - "\n", - "node = tempy.nodes[6]\n", - "# plot_look_up_table(node)\n", - "# plot_schemata(node)\n", - "print(node.look_up_table())\n", - "print(node.schemata_look_up_table(type=\"pi\"))\n", - "print(node)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.21875\n" - ] - } - ], - "source": [ - "# find bias of the lut of node\n", - "node.look_up_table()\n", - "print(node.bias())\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "generating permutations of output lists for incomplete data" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# # need to modify the output list from data function to include the this following function\n", - "# def from_output_list_with_missing_data(outputs=list(), *args, **kwargs):\n", - "# \"\"\"\n", - "# Instanciate a Boolean Node from a output transition list.\n", - "\n", - "# For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing.\n", - "\n", - "# Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs.\n", - "\n", - "# Args:\n", - "# outputs (list) : The transition outputs of the node.\n", - "\n", - "# Returns:\n", - "# (BooleanNode) : the instanciated object.\n", - "\n", - "# Example:\n", - "# >>> BooleanNode.from_output_list_with_missing_data(outputs=[0,0,0,'-',1], name=\"AND\")\n", - "# \"\"\"\n", - "# id = kwargs.pop(\"id\") if \"id\" in kwargs else 0\n", - "# name = kwargs.pop(\"name\") if \"name\" in kwargs else \"x\"\n", - "# k = int(np.ceil(np.log2(len(outputs))))\n", - "# inputs = kwargs.pop(\"inputs\") if \"inputs\" in kwargs else [(x + 1) for x in range(k)]\n", - "# state = kwargs.pop(\"state\") if \"state\" in kwargs else False\n", - "\n", - "# # Replace 'None', '-', '#', or 'x' with '-'.\n", - "# for i in range(len(outputs)):\n", - "# if outputs[i] in [None, \"-\", \"#\", \"x\"]:\n", - "# outputs[i] = \"-\" # Placeholder value for missing data\n", - "# print(\n", - "# \"Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.\"\n", - "# )\n", - "\n", - "# # Generate extra lines in the table to account for missing lines\n", - "# if len(outputs) < 2**k:\n", - "# print(\n", - "# f\"Some of the lines in the data are missing and have been replaced with the placeholder value '-' for upto 2^k lines. i.e. the total lines inputted are {len(outputs)}, then the function will generate the missing rows for upto 2^{k} = {2**k} lines.\"\n", - "# )\n", - "# outputs.extend([\"-\"] * (2**k - len(outputs)))\n", - "\n", - "# return BooleanNode(\n", - "# id=id,\n", - "# name=name,\n", - "# k=k,\n", - "# inputs=inputs,\n", - "# state=state,\n", - "# outputs=outputs,\n", - "# *args,\n", - "# **kwargs,\n", - "# )\n", - "\n", - "\n", - "# def generate_output_list_permutations(incomplete_boolean_node):\n", - "# # generating all possible output_list permutations for the incomplete boolean node.\n", - "\n", - "# outputs = incomplete_boolean_node.outputs\n", - "# print(outputs)\n", - "# missing_data_indices = [i for i, x in enumerate(outputs) if x == '-']\n", - "# # output_list_permutations = [outputs.copy() for _ in range(2 ** len(missing_data_indices))]\n", - "\n", - "# #generating binarytable for size: no. of missing values\n", - "# table=[]\n", - "# output_list_permutations=[]\n", - "# for i in range(2 ** len(missing_data_indices)):\n", - "# row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))]\n", - "# table.append(row)\n", - "# output_list_permutations.append(outputs.copy())\n", - "# for j in range(len(missing_data_indices)):\n", - "# output_list_permutations[i][missing_data_indices[j]] = table[i][j]\n", - "# return output_list_permutations" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0, 0, None, 1, 1, 0]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "incomplete_output = [0, 0, None, 1, 1, 0]\n", - "# incomplete_output = tempy.nodes[5].outputs.copy()\n", - "incomplete_output\n", - "\n", - "\n", - "# creating a boolean node for incomplete data\n", - "# incomplete_boolean_node = from_output_list_with_missing_data(incomplete_output)\n", - "# print(incomplete_boolean_node)\n", - "# output_list_permutations = generate_output_list_permutations(incomplete_boolean_node)\n", - "# print(f'Following are the pemutations of the incomplete output list of length:{len(output_list_permutations)}')\n", - "# output_list_permutations" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# incomplete_boolean_node.look_up_table()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Added missing data code to the from_output_list funciton in boolean_node.py. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Input Output\n", - "0 #0 0\n", - "1 #1 1\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " In: Out:\n", - "0 00 0\n", - "1 01 1\n", - "2 10 0\n", - "3 11 1\n" - ] - } - ], - "source": [ - "# # testing modified from_output_list function\n", - "# incomplete_output = [0,0, None, 1,1,0]\n", - "# incomplete_boolean_node = BooleanNode.from_output_list(incomplete_output)\n", - "# print(incomplete_boolean_node.outputs)\n", - "# incomplete_boolean_node.look_up_table()\n", - "AND = BooleanNode.from_output_list([0, 1, 0, 1])\n", - "print(AND.schemata_look_up_table(type=\"pi\"))\n", - "plot_look_up_table(AND)\n", - "print(AND.look_up_table())" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('00--', '0'), ('1--1', '1'), ('11--', '0')]\n", - "Clashing output values for entry: 1101\n", - "Clashing output values for entry: 1111\n", - "[('0000', '0'), ('0001', '0'), ('0010', '0'), ('0011', '0'), ('0100', '?'), ('0101', '?'), ('0110', '?'), ('0111', '?'), ('1000', '?'), ('1001', '1'), ('1010', '?'), ('1011', '1'), ('1100', '0'), ('1101', '!'), ('1110', '0'), ('1111', '!')]\n" - ] - } - ], - "source": [ - "# # partial_lut = [('1--','1'),('101','0'),('011','0'),('01-','1')]\n", - "# # partial_lut = [('0--0','0'),('1--1','0'),('0111','1'),('0011','1')]\n", - "partial_lut = [('00--', '0'), ('1--1', '1'), ('11--', '0')]\n", - "# partial_lut = [('00--', '0'), ('01--', '1'), ('10--', '1'), ('11--', '0')]\n", - "print(partial_lut)\n", - "generated_lut = fill_out_lut(partial_lut)\n", - "print(generated_lut)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('---1', '0'), ('-1--', '0'), ('1---', '0'), ('--1-', '0'), ('0000', '1')]\n", - "0000 0\n", - "0001 0\n", - "0010 0\n", - "0011 0\n", - "0100 ?\n", - "0101 ?\n", - "0110 ?\n", - "0111 ?\n", - "1000 ?\n", - "1001 1\n", - "1010 ?\n", - "1011 1\n", - "1100 0\n", - "1101 !\n", - "1110 0\n", - "1111 !\n" - ] - } - ], - "source": [ - "# write a function that converts datya in the example form 00-- 0\\n1--1 1\\n11-- 0 to this example form: ('00--','0'),('1--1','1'),('11--','0')\n", - "def from_example_form_to_list(example_form):\n", - " example_form = example_form.split(\"\\n\")\n", - " example_form = [tuple(x.split(\" \")) for x in example_form]\n", - " return example_form\n", - "\n", - "\n", - "print(from_example_form_to_list(\"---1 0\\n-1-- 0\\n1--- 0\\n--1- 0\\n0000 1\"))\n", - "\n", - "\n", - "# write a function that converts data in the example form ('00--','0'),('1--1','1'),('11--','0') to this example form: 00-- 0\\n1--1 1\\n11-- 0\n", - "def from_list_to_example_form(example_form):\n", - " example_form = [x[0] + \" \" + x[1] for x in example_form]\n", - " example_form = \"\\n\".join(example_form)\n", - " return example_form\n", - "\n", - "\n", - "print(from_list_to_example_form(generated_lut))" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "16\n" - ] - }, - { - "data": { - "text/plain": [ - "['0',\n", - " '0',\n", - " '0',\n", - " '0',\n", - " '?',\n", - " '?',\n", - " '?',\n", - " '?',\n", - " '?',\n", - " '1',\n", - " '?',\n", - " '1',\n", - " '0',\n", - " '!',\n", - " '0',\n", - " '!']" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(len(generated_lut))\n", - "output = []\n", - "output = [generated_lut[i][1] for i in range(len(generated_lut))]\n", - "output\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Clashing output values for entry: 1101\n", - "Clashing output values for entry: 1111\n", - "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '0', '!', '0', '!']\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
In:Out:
000000
100010
200100
300110
40100?
50101?
60110?
70111?
81000?
910011
101010?
1110111
1211000
131101!
1411100
151111!
\n", - "
" - ], - "text/plain": [ - " In: Out:\n", - "0 0000 0\n", - "1 0001 0\n", - "2 0010 0\n", - "3 0011 0\n", - "4 0100 ?\n", - "5 0101 ?\n", - "6 0110 ?\n", - "7 0111 ?\n", - "8 1000 ?\n", - "9 1001 1\n", - "10 1010 ?\n", - "11 1011 1\n", - "12 1100 0\n", - "13 1101 !\n", - "14 1110 0\n", - "15 1111 !" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "generated_lut = fill_out_lut(partial_lut)\n", - "output_list = [x[1] for x in generated_lut]\n", - "print(output_list)\n", - "generated_node = BooleanNode.from_output_list(output_list)\n", - "generated_node.look_up_table()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Clashing output values for entry: 1101\n", - "Clashing output values for entry: 1111\n", - "The LUT is incomplete. Missing values are represented by '?'\n", - "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '0', '!', '0', '!']\n", - " In: Out:\n", - "0 0000 0\n", - "1 0001 0\n", - "2 0010 0\n", - "3 0011 0\n", - "4 0100 ?\n", - "5 0101 ?\n", - "6 0110 ?\n", - "7 0111 ?\n", - "8 1000 ?\n", - "9 1001 1\n", - "10 1010 ?\n", - "11 1011 1\n", - "12 1100 0\n", - "13 1101 !\n", - "14 1110 0\n", - "15 1111 !\n" - ] - } - ], - "source": [ - "generated_node = BooleanNode.from_partial_lut(partial_lut)\n", - "print(generated_node.outputs)\n", - "print(generated_node.look_up_table())" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['0', '1', '0', '1']" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "logic = {\n", - " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", - " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", - " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", - "}\n", - "# Instanciate the BooleanNetwork\n", - "bn = BooleanNetwork.from_dict(logic)\n", - "bn.nodes[0].outputs" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The LUT is incomplete. Missing values are represented by '?'\n", - "\n" - ] - } - ], - "source": [ - "bn = BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], name=\"EG\")\n", - "print(bn)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "source": [ - "## Instantiating a Boolean Network \n", - "\n", - "The Boolean Network is created using the BooleanNetwork.from_dict() function which takes a Logic Dictionary as input. \n", - "\n", - "The logic dict is in the following format:\n", - "\n", - "```python\n", - "logic = {\n", - " 0: {'name': 'A', 'in': [1,0], 'out': [0, 1, 0,1]},\n", - " 1: {'name': 'B', 'in': [0,2], 'out': [0, 1, 0, 1]},\n", - " 2: {'name': 'C', 'in': [0,1,2], 'out': [0, 1, 1, 0, 0, 1, 1, 0]}\n", - " }\n", - "```\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [], - "source": [ - "\n", - "def generate_logic_dict_from_boolean_node(boolean_node, k = 5, nnodes= 8):\n", - " \n", - " logic = {}\n", - " \n", - " logic= { 0: {\n", - " 'name': boolean_node.name,\n", - " 'in': [input_node for input_node in boolean_node.inputs],\n", - " 'out': boolean_node.outputs\n", - " }\n", - " }\n", - " return logic\n", - "\n", - "logic = generate_logic_dict_from_boolean_node(generated_node)\n", - "print(logic)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SoftComputing", - "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": 2 -} From d894bdbe0ef942b4d13e6b528d6fea549695bedc Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Thu, 20 Jun 2024 20:24:15 -0400 Subject: [PATCH 09/14] retained old behaviour in BooleanNetwork.from_cnet and added a partial_lut = false keyword. split Boolean_node.from_partial_lut into three functions added a few tests. need to add more. --- cana/boolean_network.py | 217 +++-- cana/boolean_node.py | 427 ++++++---- cana/datasets/bio.py | 14 +- cana/datasets/partial_LUT_demo_nodes.txt | 62 -- cana/drawing/schema_vis.py | 5 +- cana/utils.py | 47 +- tests/test_boolean_node.py | 711 ++++++++++++---- tutorials/Generating from Partial LUTs.ipynb | 808 +++++++++++++------ tutorials/partial_LUT_demo_nodes.txt | 127 +++ 9 files changed, 1684 insertions(+), 734 deletions(-) delete mode 100644 cana/datasets/partial_LUT_demo_nodes.txt create mode 100644 tutorials/partial_LUT_demo_nodes.txt diff --git a/cana/boolean_network.py b/cana/boolean_network.py index 872afb3..2a1bf8f 100644 --- a/cana/boolean_network.py +++ b/cana/boolean_network.py @@ -6,6 +6,7 @@ Main class for Boolean network objects. """ + # Copyright (C) 2021 by # Rion Brattig Correia # Alex Gates @@ -67,12 +68,12 @@ def __init__( constants=None, Nconstants=None, keep_constants=False, + partial_lut=False, bin2num=None, num2bin=None, - verbose=False, # Verbose mode for debugging purposes + verbose=False, # Verbose mode for debugging purposes *args, - **kwargs - # TODO: [SRI] ask Jordan if we should add a requirement called complete = True or False so as to generate patial look up tables based on the completeness of the network + **kwargs, ): # NOTE: *args and **kwargs don't do anything. I'm not sure why they wre added here, so I'm not going to remove them. @@ -96,6 +97,11 @@ def __init__( ) self.Nstates = 2**Nnodes # Number of possible states in the network 2^N + # + self.partial_lut = ( + partial_lut # Generate with '?' output values a.k.a. partial look up tables + ) + # self.verbose = verbose @@ -148,13 +154,16 @@ def __str__(self): # I/O Methods # @classmethod - def from_file(self, file, type="cnet", keep_constants=True, **kwargs): + def from_file( + self, file, type="cnet", keep_constants=True, partial_lut=False, **kwargs + ): """ Load the Boolean Network from a file. Args: file (string) : The name of a file containing the Boolean Network. type (string) : The type of file, either 'cnet' (default) or 'logical' for Boolean logical rules. + partial_lut (bool) : Generate with '?' output values a.k.a. partial look up tables. Defaults to False. Returns: BooleanNetwork (object) : The boolean network object. @@ -165,7 +174,10 @@ def from_file(self, file, type="cnet", keep_constants=True, **kwargs): with open(file, "r") as infile: if type == "cnet": return self.from_string_cnet( - infile.read(), keep_constants=keep_constants, **kwargs + infile.read(), + keep_constants=keep_constants, + partial_lut=partial_lut, + **kwargs, ) elif type == "logical": return self.from_string_boolean( @@ -173,15 +185,19 @@ def from_file(self, file, type="cnet", keep_constants=True, **kwargs): ) @classmethod - def from_string_cnet(self, string, keep_constants=True, **kwargs): + def from_string_cnet( + self, string, keep_constants=True, partial_lut=False, **kwargs + ): """ - Instanciates a Boolean Network from a string in cnet format. + Instanciates a Boolean Network from a string in cnet format. The cnet format is similar to the Berkeley Logic Interchange Format (BLIF). This function generates a Logic dictionary from the string and uses the :func:`~cana.boolean_network.BooleanNetwork.from_dict` method to generate the Boolean Network object. Args: string (string): A cnet format representation of a Boolean Network. + partial_lut (bool): Generate with '?' output values a.k.a. partial look up tables. Defaults to False. + Returns: (BooleanNetwork) @@ -224,70 +240,117 @@ def from_string_cnet(self, string, keep_constants=True, **kwargs): for jnode in range(indegree): logic[inode]["in"].append(int(line.split()[3 + jnode]) - 1) - # to generate with '?' output values - logic[inode]["out"] = [ - '?' for i in range(2**indegree) if indegree > 0 - ] # activate this for '?' output values - - logic_line = network_file.readline().strip() - - if indegree <= 0: - if logic_line == "": - logic[inode]["in"] = [inode] - logic[inode]["out"] = [0, 1] + # to generate with '?' output values a.k.a. partial look up tables. If partial_lut is False, it generates with Prime Implicants(PI)(default) + if partial_lut: + logic[inode]["out"] = [ + "?" for i in range(2**indegree) if indegree > 0 + ] # activate this for '?' output values + + logic_line = network_file.readline().strip() + + if indegree <= 0: + if logic_line == "": + logic[inode]["in"] = [inode] + logic[inode]["out"] = [0, 1] + else: + logic[inode]["out"] = [int(logic_line)] else: - logic[inode]["out"] = [int(logic_line)] + while ( + logic_line != "\n" + and logic_line != "" + and len(logic_line) > 1 + ): + # Check for clashing entries. + for nlogicline in expand_logic_line(logic_line): + if logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] in [ + "?", + None, + 2, + "-", + ]: # assigns output value if it is not assigned + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] = int(nlogicline.split()[1]) + elif ( + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] + == int(nlogicline.split()[1]) + ): # if the output value is already assigned and is the same as the new output value + pass + else: # if the output value is already assigned and is different from the new output value + print( + "Entry clash in node ", + (inode + 1), + " for ", + {nlogicline.split()[0]}, + " i.e. State number: ", + binstate_to_statenum(nlogicline.split()[0]), + ) + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] = "!" + + logic_line = network_file.readline().strip() + else: - while ( - logic_line != "\n" - and logic_line != "" - and len(logic_line) > 1 - ): - # Check for clashing entries. - for nlogicline in expand_logic_line(logic_line): - if logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] in ['?', None, 2, '-']: # assigns output value if it is not assigned - logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = int(nlogicline.split()[1]) - elif logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] == int(nlogicline.split()[1]): # if the output value is already assigned and is the same as the new output value - pass - else: # if the output value is already assigned and is different from the new output value - print("Entry clash in node ",(inode+1)," for ",{nlogicline.split()[0]}," i.e. State number: ",binstate_to_statenum(nlogicline.split()[0])) - logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = '!' - - logic_line = network_file.readline().strip() - # TODO: [SRI] check if I need to add a Prime Implicant condition in the function - ## to generate with Prime Implicants(PI) - # logic[inode]["out"] = [ - # '0' for i in range(2**indegree) if indegree > 0 - # ] - - # logic_line = network_file.readline().strip() - - # if indegree <= 0: - # if logic_line == "": - # logic[inode]["in"] = [inode] - # logic[inode]["out"] = [0, 1] - # else: - # logic[inode]["out"] = [int(logic_line)] - # else: - # while ( - # logic_line != "\n" - # and logic_line != "" - # and len(logic_line) > 1 - # ): - # # Check for clashing entries. - # for nlogicline in expand_logic_line(logic_line): - # if logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] in ['?', None, 2, '-','0']: # assigns output value if it is not assigned - # logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = int(nlogicline.split()[1]) - # elif logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] == int(nlogicline.split()[1]): # if the output value is already assigned and is the same as the new output value - # pass - # else: # if the output value is already assigned and is different from the new output value - # print("Entry clash in node ",(inode+1)," for ",{nlogicline.split()[0]}," i.e. State number: ",binstate_to_statenum(nlogicline.split()[0])) - # logic[inode]["out"][binstate_to_statenum(nlogicline.split()[0])] = '1' - - # logic_line = network_file.readline().strip() - # .e = end of file - elif ".e" in line: + # to generate with Prime Implicants(PI) + logic[inode]["out"] = [ + "0" for i in range(2**indegree) if indegree > 0 + ] + + logic_line = network_file.readline().strip() + if indegree <= 0: + if logic_line == "": + logic[inode]["in"] = [inode] + logic[inode]["out"] = [0, 1] + else: + logic[inode]["out"] = [int(logic_line)] + else: + while ( + logic_line != "\n" + and logic_line != "" + and len(logic_line) > 1 + ): + # Check for clashing entries. + for nlogicline in expand_logic_line(logic_line): + if logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] in [ + "?", + None, + 2, + "-", + "0", + ]: # assigns output value if it is not assigned + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] = int(nlogicline.split()[1]) + elif ( + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] + == int(nlogicline.split()[1]) + ): # if the output value is already assigned and is the same as the new output value + pass + else: # if the output value is already assigned and is different from the new output value + print( + "Entry clash in node ", + (inode + 1), + " for ", + {nlogicline.split()[0]}, + " i.e. State number: ", + binstate_to_statenum(nlogicline.split()[0]), + ) + logic[inode]["out"][ + binstate_to_statenum(nlogicline.split()[0]) + ] = "1" + + logic_line = network_file.readline().strip() + elif ".e" in line: break line = network_file.readline() @@ -692,9 +755,9 @@ def conditional_effective_graph( # and update the conditional effective graph with the new edge effectiveness values for i in range(newk): - conditional_eg[new_successor_inputs[i]][n][ - "weight" - ] = new_edge_effectiveness[i] + conditional_eg[new_successor_inputs[i]][n]["weight"] = ( + new_edge_effectiveness[i] + ) # now update the conditioned_logic in case these nodes are further modified by additional conditioned variables conditioned_logic[n]["in"] = new_successor_inputs @@ -1438,7 +1501,7 @@ def feedback_vertex_set_driver_nodes( max_search=11, keep_self_loops=True, *args, - **kwargs + **kwargs, ): """The minimum set of necessary driver nodes to control the network based on Feedback Vertex Set (FVS) theory. @@ -1689,9 +1752,9 @@ def inv_eff_weight_func(pathlength): # once the lightcone includes the target node on the effective shortest path, # then for all other steps the effective path is the best - impact_matrix[ - 1, list(range(eff_path_steps, n_steps + 1)), itar - ] = inv_eff_weight_func(Geff_shortest_dist[target]) + impact_matrix[1, list(range(eff_path_steps, n_steps + 1)), itar] = ( + inv_eff_weight_func(Geff_shortest_dist[target]) + ) return impact_matrix[:, 1:] @@ -1771,7 +1834,7 @@ def dynamics_canalization_map(self, output=None, simplify=True): DCM.add_edge( in_nei[0], out_nei[1], - **{"type": "simplified", "mode": "selfloop"} + **{"type": "simplified", "mode": "selfloop"}, ) # Link variables nodes directly elif not any([DCM.nodes[tn]["type"] == "fusion" for tn in in_nei]): @@ -1779,7 +1842,7 @@ def dynamics_canalization_map(self, output=None, simplify=True): DCM.add_edge( in_nei[0], out_nei[1], - **{"type": "simplified", "mode": "direct"} + **{"type": "simplified", "mode": "direct"}, ) # Remove Isolates isolates = list(nx.isolates(DCM)) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index e78aaea..1b92861 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -6,6 +6,7 @@ Main class for Boolean node objects. """ + # Copyright (C) 2021 by # Rion Brattig Correia # Alex Gates @@ -14,7 +15,7 @@ # MIT license. from __future__ import division -from itertools import combinations, compress, product +from itertools import combinations, compress, islice, product, permutations from statistics import mean import networkx as nx @@ -31,6 +32,8 @@ ) from cana.utils import input_monotone, ncr, fill_out_lut import random +import warnings +from math import comb class BooleanNode(object): @@ -48,7 +51,7 @@ def __init__( network=None, verbose=False, *args, - **kwargs + **kwargs, ): self.id = id # the id of the node self.name = name # the name of the node @@ -74,7 +77,7 @@ def __init__( ) # If all outputs are either positive or negative, the node is treated as a constant. - if (len(set(outputs)) == 1) or (constant): + if (len(set(outputs)) == 1 and ("?" not in outputs)) or (constant): self.set_constant(constant=True, state=outputs[0]) else: self.set_constant(constant=False) @@ -113,10 +116,6 @@ def __str__(self): def from_output_list(self, outputs=list(), *args, **kwargs): """ Instanciate a Boolean Node from a output transition list. - - For missing data labeled as '#', '-', None, or 'x': In this case, we replace the missing data with a placeholder value, such as '-'. This allows us to maintain the structure of the outputs list while indicating that the data is missing. - - Complete line missing: If a complete line is missing from the outputs list, we can generate the missing rows as incomplete data. This can be done by extending the outputs list with the placeholder value '-' until it reaches the expected length of 2^k, where k is the number of inputs. Args: outputs (list) : The transition outputs of the node. @@ -125,27 +124,23 @@ def from_output_list(self, outputs=list(), *args, **kwargs): (BooleanNode) : the instanciated object. Example: - >>> BooleanNode.from_output_list(outputs=[0,0,0,'-',1], name="EG") + >>> BooleanNode.from_output_list(outputs=[0,0,0,1], name="EG") """ id = kwargs.pop("id") if "id" in kwargs else 0 name = kwargs.pop("name") if "name" in kwargs else "x" - k = int(np.ceil(np.log2(len(outputs)))) + k = int(np.log2(len(outputs))) + + # checking if length of outputs is a power of 2, else raising an error. + if 2**k != len(outputs): + raise ValueError( + "The number of outputs should be a power of 2. The length of the outputs list should be 2^k." + ) + inputs = ( kwargs.pop("inputs") if "inputs" in kwargs else [(x + 1) for x in range(k)] ) state = kwargs.pop("state") if "state" in kwargs else False - # Replace 'None', '-', '#', or 'x' with '-'. - for i , output in enumerate(outputs): - if output in [None, '-', '#', 'x']: - outputs[i] = '-' # Placeholder value for missing data - print("Some of the lines contain data in the form of 'x', '#', None or '-'. These have been replaced with the placeholder value '-'. for internal consistency.") - - # Generate extra lines in the table to account for missing lines - if len(outputs) < 2**k: - print(f"The total lines inputted are {len(outputs)}. Generating the missing rows for upto 2^{k} = {2**k} lines with placeholder value '-'.") - outputs.extend(['-'] * (2**k - len(outputs))) - return BooleanNode( id=id, name=name, @@ -154,122 +149,8 @@ def from_output_list(self, outputs=list(), *args, **kwargs): state=state, outputs=outputs, *args, - **kwargs + **kwargs, ) - - def from_partial_lut(partial_lut, fill_missing_output_randomly = False, required_node_bias = None, required_effective_connectivity= None,verbose= True, *args, **kwargs): - """ - Instantiate a Boolean Node from a partial look-up table. - - Uses the fill_out_lut function to complete the look-up table. Extracts the output list from the completed look-up table. Then instantiates the Boolean Node from the output list using the from_output_list method. - - Args: - partial_lut (list) : A partial look-up table of the node. - fill_missing_output_randomly (bool) : If True, missing output values are filled with random 0 or 1. If False, missing output values are filled with '?'. - required_node_bias (float) : The required node bias to fill the missing output values with. If None, missing output values are filled with '?', or randomly if fill_missing_output is True. - required_effective_connectivity (float) : The required effective connectivity to fill the missing output values with. It will generate a node with the closest possible effective connectivity to the required effective connectivity. - verbose (bool) : If True, print additional information. Default is True. - - Returns: - (BooleanNode) : the instantiated object. - - Example: - >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], required_node_bias=0.5, verbose=True, name="EG") - >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], fill_missing_output_randomly=True, verbose=False, name="EG") - >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], required_effective_connectivity=0.5, verbose=True, name="EG") - - Note: - The partial look-up table should be a list of tuples where each tuple contains a binary input state and the corresponding output value. For example, [('00', 0), ('01', 1), ('11', 1)]. - The required node bias should be a float value between 0 and 1. - The required effective connectivity should be a float value between 0 and 1. - The fill_missing_output_randomly should be a boolean value. - - # TODO : [SRI] add tests for this - """ - - # Checking if more than one out of required_effective_connectivity, requried_node_bias and fill_missing_output_randomly are True, then raise an error. - if sum([required_effective_connectivity is not None, required_node_bias is not None, fill_missing_output_randomly]) > 1: - raise ValueError("Only one of required_effective_connectvity, required_node_bias and fill_missing_output_randomly can be True. Please set the rest to False.") - - - generated_lut = fill_out_lut(partial_lut, verbose=False) - output_list = [x[1] for x in generated_lut] - - generated_node = BooleanNode.from_output_list(output_list, *args, **kwargs) - - # Fill missing output values with the specified bias or with specified effective connectivity or randomly - - if required_node_bias is not None: # If required node bias is specified, then fill missing output values with the specified bias. - - # Checking if required node bias is within the achievable bias range of the node. - - # Calculating max achievable bias - max_achievable_output = ['1' if output == '?' else output for output in generated_node.outputs] - max_achievable_bias = sum(map(int, max_achievable_output))/2**generated_node.k - min_achievable_bias = generated_node.bias(verbose=False) - - # Calculating the number of '1' required to achieve the required bias. - required_ones = int(required_node_bias * 2**generated_node.k) - current_ones = generated_node.outputs.count('1') - - # Checking if the required bias is achievable. - if required_node_bias > max_achievable_bias: - if verbose: - print(f"Required Node Bias is greater than the maximum achievable bias ({max_achievable_bias}) of the node. Generating with the maximum achievable bias.") - required_node_bias = max_achievable_bias - - elif required_node_bias < min_achievable_bias: - min_achievable_bias = generated_node.bias(verbose=False) - if verbose: - print(f"Required Node Bias is lower than the minimum achievable bias (bias = {min_achievable_bias}) of the node. Generating with the minimum achievable bias.") - required_node_bias = min_achievable_bias - - # Fill the missing output values to achieve the required bias as closely as possible. - required_ones = int(required_node_bias * 2**generated_node.k) # recalculating in case the required bias was adjusted in the above steps. - ones_to_be_generated = required_ones - current_ones - number_of_missing_values = generated_node.outputs.count('?') - - missing_output_values = ['1'] * ones_to_be_generated + ['0'] * (number_of_missing_values - ones_to_be_generated) # creating a shuffled list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias. - random.shuffle(missing_output_values) - generated_node.outputs = [missing_output_values.pop() if output== '?' else output for output in generated_node.outputs] - - if verbose: - print(f"Generated the node with a bias of {generated_node.bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {required_node_bias}.") - - elif fill_missing_output_randomly: - # Replace '?' in generated_node.outputs with 0 or 1 randomly - generated_node.outputs = [random.choice(['0', '1']) if output == '?' else output for output in generated_node.outputs] - - elif required_effective_connectivity is not None: - generated_outputs = generated_node.outputs.copy() - missing_output_indices = [i for i, x in enumerate(generated_outputs) if x == '?'] - # print(f"Missing output indices = {missing_output_indices}." if verbose else None) - - missing_output_count = generated_outputs.count('?') - # print(f"No. of '?' in output = {missing_output_count}.") - permutations = list(product(*[('0', '1')] * (missing_output_count))) - # print(permutations) - generated_node_permutations = [None] * len(permutations) - - for count, permutation in enumerate(permutations): - for i, index in enumerate(missing_output_indices): - generated_outputs[index] = permutation[i] - generated_node_permutations[count] = BooleanNode.from_output_list(generated_outputs) - - # print(f"Total output permutations generated = {len(generated_node_permutations)}.") - - permutation_effective_connectivity = [x.effective_connectivity() for x in generated_node_permutations] - closest_value = min(permutation_effective_connectivity, key=lambda x: abs(x - required_effective_connectivity)) - closest_index = permutation_effective_connectivity.index(closest_value) - - generated_node = generated_node_permutations[closest_index] - print(f"Generated the node with the closest possible effective connectivity of {generated_node.effective_connectivity()}." if verbose else None) - - if '?' in generated_node.outputs: - print("The LUT is incomplete. Missing values are represented by '?'." if verbose else None) - return generated_node - - def set_constant(self, constant=True, state=None): """Sets whether the node is to be treated as a contant @@ -558,14 +439,14 @@ def look_up_table(self): return df def schemata_look_up_table( - self, type="pi", pi_symbol="#", ts_symbol_list=["\u030A", "\u032F"] + self, type="pi", pi_symbol="#", ts_symbol_list=["\u030a", "\u032f"] ): """Returns the simplified schemata Look Up Table (LUT) Args: type (string) : The type of schemata to return, either Prime Implicants ``pi`` or Two-Symbol ``ts``. Defaults to 'pi'. pi_symbol (str) : The Prime Implicant don't care symbol. Default is ``#``. - ts_symbol_list (list) : A list containing Two Symbol permutable symbols. Default is ``["\u030A", "\u032F"]``. + ts_symbol_list (list) : A list containing Two Symbol permutable symbols. Default is ``["\u030a", "\u032f"]``. Returns: (pandas.DataFrame or Latex): the schemata LUT @@ -580,10 +461,11 @@ def schemata_look_up_table( See also: :func:`look_up_table` """ - # Check if the outputs contain '?' and generate an error message if it does. - if '?' in self.outputs: - print("Error (schemata_look_up_table): The outputs contain missing values. Please fill the missing values before generating the schemata look-up table.") - return False + # Check if the outputs contain '?' and generate an error message if it does. + if "?" in self.outputs: + raise ValueError( + "The look-up table contains '?' values. The schemata look-up table cannot be generated." + ) r = [] # Prime Implicant LUT @@ -712,7 +594,7 @@ def canalizing_map(self, output=None): "value": 0, "constant": self.constant, "group": self.id, - } + }, ) if output is None or output == 1: @@ -725,7 +607,7 @@ def canalizing_map(self, output=None): "value": 1, "constant": self.constant, "group": self.id, - } + }, ) tid = 0 @@ -772,7 +654,7 @@ def canalizing_map(self, output=None): "type": "threshold", "tau": tau, "group": self.id, - } + }, ) # Add Edges from Threshold node to output @@ -802,7 +684,7 @@ def canalizing_map(self, output=None): "mode": "input", "value": iout, "group": self.id, - } + }, ) G.add_edge(iname, tname, **{"type": "literal"}) @@ -832,7 +714,7 @@ def canalizing_map(self, output=None): "mode": "input", "value": 0, "group": self.id, - } + }, ) G.add_edge(iname, fname, **{"type": "fusing"}) G.add_edge(fname, tname, **{"type": "fused"}) @@ -864,7 +746,7 @@ def canalizing_map(self, output=None): "mode": "input", "value": 1, "group": self.id, - } + }, ) G.add_edge(iname, fname, **{"type": "fusing"}) G.add_edge(fname, tname, **{"type": "fused"}) @@ -967,11 +849,15 @@ def bias(self, verbose=True): :func:`~cana.boolean_network.BooleanNetwork.network_bias` """ if verbose: - if '?' in self.outputs: - print("Warning: There is a '?' value in the output. It will be treated as zero for the bias calculation.") + if "?" in self.outputs: + print( + "Warning: There is a '?' value in the output. It will be treated as zero for the bias calculation." + ) + + outputs = [ + 0 if output == "?" else output for output in self.outputs + ] # added this condition so that bias function plays nice with '?' output values. It will treat missing outputs as 0. - outputs = [0 if output == '?' else output for output in self.outputs] # added this condition so that bias function plays nice with '?' output values. It will treat missing outputs as 0. - bias = sum(map(int, outputs)) / 2**self.k return bias @@ -1057,3 +943,242 @@ def input_signs(self): ] return input_sign_list + + def from_partial_lut( + partial_lut, + fill_missing_output_randomly=False, + required_node_bias=None, + required_effective_connectivity=None, + verbose=False, + *args, + **kwargs, + ): + """ + Instantiate a Boolean Node from a partial look-up table. + + Uses the fill_out_lut function to complete the look-up table. Extracts the output list from the completed look-up table. Then instantiates the Boolean Node from the output list using the from_output_list method. + + Args: + partial_lut (list) : A partial look-up table of the node. + fill_missing_output_randomly (bool) : If True, missing output values are filled with random 0 or 1. If False, missing output values are filled with '?'. + verbose (bool) : If True, print additional information. + + Returns: + (BooleanNode) : the instantiated object. + + Example: + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], verbose=True, name="EG") + >>> BooleanNode.from_partial_lut(partial_lut=[('00', 0), ('01', 1), ('11', 1)], fill_missing_output_randomly=True, verbose=False, name="EG") + + + Note: + The partial look-up table should be a list of tuples where each tuple contains a binary input state and the corresponding output value. For example, [('00', 0), ('01', 1), ('11', 1)]. + The fill_missing_output_randomly should be a boolean value. + + # TODO : [SRI] add tests for this + """ + + generated_lut = fill_out_lut(partial_lut, verbose=False) + output_list = [x[1] for x in generated_lut] + + generated_node = BooleanNode.from_output_list(output_list, *args, **kwargs) + + # Fill missing output values with the specified bias or with specified effective connectivity or randomly + + if fill_missing_output_randomly: # TODO : [SRI] should this also return a list like the others? + # Replace '?' in generated_node.outputs with 0 or 1 randomly + generated_node.outputs = [ + random.choice(["0", "1"]) if output == "?" else output + for output in generated_node.outputs + ] + + if verbose and "?" in generated_node.outputs: + print( + "The LUT is incomplete. Missing values are represented by '?'." + if verbose + else None + ) + return generated_node + + def generate_with_required_bias( + self, + required_node_bias=None, + limit=1000, + verbose=False, + *args, + **kwargs, + ): + """ + Generate a node with the required bias. + This node takes a boolean node with "?" output values and generates all possible nodes with the missing output values filled to achieve the required bias as closely as possible. + + Args: + required_node_bias (float) : The required node bias to fill the missing output values with. + verbose (bool) : If True, print additional information. + + Returns: + (BooleanNode) : the instantiated object. + + Example: + >>> BooleanNode.generate_with_required_bias(required_node_bias=0.5, verbose=True, name="EG") + + Note: + The required node bias should be a float value between 0 and 1. + + # TODO : [SRI] check why when run in a notebook does the cell take so long to run. It says pending. and takes forever to initialize and the runtime when finished is close to zero. + """ + generated_node = self + bias = required_node_bias # making a copy for print statement at the end of function + # Checking if more than one out of required_effective_connectivity, requried_node_bias and fill_missing_output_randomly are True, then raise an error. + if required_node_bias is None: + raise ValueError( + "Please specify the required node bias to generate the node with the required bias." + ) + + if ( + required_node_bias is not None + ): # If required node bias is specified, then fill missing output values with the specified bias. + # Checking if required node bias is within the achievable bias range of the node. + + # Calculating max achievable bias + max_achievable_output = [ + "1" if output == "?" else output for output in generated_node.outputs + ] + max_achievable_bias = ( + sum(map(int, max_achievable_output)) / 2**generated_node.k + ) + + # Calculating the number of '1' required to achieve the required bias. + required_ones = int(required_node_bias * 2**generated_node.k) + current_ones = generated_node.outputs.count("1") + + min_achievable_bias = current_ones / 2**generated_node.k + min = False # flag to check if the required bias is less than the minimum achievable bias. + # Checking if the required bias is achievable. + if required_node_bias > max_achievable_bias: + if verbose: + warnings.warn( + f"Required Node Bias is greater than the maximum achievable bias ({max_achievable_bias}) of the node. Generating with the maximum achievable bias." + ) + required_node_bias = max_achievable_bias + + elif required_node_bias < min_achievable_bias: + if verbose: + warnings.warn( + f"Required Node Bias is lower than the minimum achievable bias ({min_achievable_bias}) of the node. Generating with the minimum achievable bias." + ) + required_node_bias = min_achievable_bias + min = True + + # Fill the missing output values to achieve the required bias as closely as possible. + required_ones = int( + required_node_bias * 2**generated_node.k + ) # recalculating in case the required bias was adjusted in the above steps. + ones_to_be_generated = required_ones - current_ones + number_of_missing_values = generated_node.outputs.count("?") + + missing_output_values = ( + ["1"] * ones_to_be_generated + + ["0"] * (number_of_missing_values - ones_to_be_generated) + ) # creating a list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias. + combinationsnumber = comb(number_of_missing_values, ones_to_be_generated) + + if combinationsnumber > limit: + warnings.warn( + f"Total possible permutaions = {combinationsnumber}. Selecting {limit} permutations randomly." + ) + # create a list of all possible unique arrangements of the missing output values + combinations = list(islice(set(permutations(missing_output_values)), limit)) + + generated_node_permutations = [None] * len(combinations) + + for count, combination in enumerate(combinations): + combination = list(combination) + random.shuffle(combination) + generated_outputs = generated_node.outputs.copy() + for i, output in enumerate(generated_node.outputs): + if output == "?": + generated_outputs[i] = combination.pop() + generated_node_permutations[count] = BooleanNode.from_output_list( + generated_outputs, *args, **kwargs + ) # generating a list of nodes with all possible permutations of the missing output values that achieve the required bias. + + if verbose: + if min: + print( + f"Generated {len(generated_node_permutations)} node(s) with a bias of {generated_node_permutations[0].bias(verbose=False)}. This is the closest achievable bias to the required bias of {bias}." + ) + else: + print( + f"Generated {len(generated_node_permutations)} node(s) with a bias of {generated_node_permutations[0].bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {bias}." + ) + return generated_node_permutations + + def generate_with_required_effective_connectivity( + self, + required_effective_connectivity=None, + limit=50, + verbose=False, + *args, + **kwargs, + ): + """ + Generate a node with the required effective connectivity. + This node takes a boolean node with "?" output values and generates all possible nodes with the missing output values filled to achieve the required effective connectivity as closely as possible. + + Args: + required_effective_connectivity (float) : The required effective connectivity to fill the missing output values with. It will generate a node with the closest possible effective connectivity to the required effective connectivity. + verbose (bool) : If True, print additional information. + + Returns: + (BooleanNode) : the instantiated object. + + Example: + >>> BooleanNode.generate_with_required_effective_connectivity(required_effective_connectivity=0.5, verbose=True, name="EG") + + Note: + The required effective connectivity should be a float value between 0 and 1. + + # TODO : [SRI] to cover the entire space of permutations evenly, what if i fill each node randomly and calculate the effective connectivity . then add them to a list of all nodes with sufficiently close effective connectivity? This option will only be activated if the calculated permutation space goes beyond a predecided threshold. + """ + + generated_node = self + if required_effective_connectivity is not None: + generated_outputs = generated_node.outputs.copy() + missing_output_indices = [ + i for i, x in enumerate(generated_outputs) if x == "?" + ] + # print(f"Missing output indices = {missing_output_indices}." if verbose else None) + + missing_output_count = generated_outputs.count("?") + # print(f"No. of '?' in output = {missing_output_count}.") + missing_permutations = list(product(*[("0", "1")] * (missing_output_count))) + # print(permutations) + generated_node_permutations = [None] * len(missing_permutations) + + for count, missing_permutation in enumerate(missing_permutations): + for i, index in enumerate(missing_output_indices): + generated_outputs[index] = missing_permutation[i] + generated_node_permutations[count] = BooleanNode.from_output_list( + generated_outputs, *args, **kwargs + ) # generating a list of nodes with all possible permutations of the missing output values. + + # print(f"Total output permutations generated = {len(generated_node_permutations)}.") + + permutation_effective_connectivity = [ + x.effective_connectivity() for x in generated_node_permutations + ] + closest_value = min( + permutation_effective_connectivity, + key=lambda x: abs(x - required_effective_connectivity), + ) + closest_index = permutation_effective_connectivity.index(closest_value) + + generated_node = generated_node_permutations[closest_index] + print( + f"Generated the node with the closest possible effective connectivity of {generated_node.effective_connectivity()}." + if verbose + else None + ) + + return generated_node diff --git a/cana/datasets/bio.py b/cana/datasets/bio.py index bfe8a42..e4cfe4a 100644 --- a/cana/datasets/bio.py +++ b/cana/datasets/bio.py @@ -7,6 +7,7 @@ """ + # Copyright (C) 2021 by # Alex Gates # Rion Brattig Correia @@ -22,19 +23,6 @@ """ Make sure we know what the current directory is """ -def PARTIAL_LUTS_DEMO(): - """ - A txt file with different types of Partial LUTs to demo the Partial Lut generation function. - - Returns: - (BooleanNetwork) - """ - return BooleanNetwork.from_file( - _path + "/partial_LUT_demo_nodes.txt", - name="Partial LUTs Demo", - keep_constants=True, - ) - def THALIANA(): """Boolean network model of the control of flower morphogenesis in Arabidopsis thaliana diff --git a/cana/datasets/partial_LUT_demo_nodes.txt b/cana/datasets/partial_LUT_demo_nodes.txt deleted file mode 100644 index 0c80d0f..0000000 --- a/cana/datasets/partial_LUT_demo_nodes.txt +++ /dev/null @@ -1,62 +0,0 @@ -# total number of nodes -.v 7 - -# labels of nodes and names of corresponding components -.l 1 One -.l 2 Two -.l 3 Three -.l 4 Four -.l 5 Five -.l 6 Six -.l 7 Seven - -# 1 = One -.n 1 0 -1 - -# 2 = Two -.n 2 0 -1 - -# 3 = Three -.n 3 0 -1 - -# 4 = Four -.n 4 0 -1 - -# 5 = Five -.n 5 3 3 4 2 -000 1 -0-0 0 -1-0 1 -111 1 - -# 6 = Six -.n 6 2 1 2 -00 0 -01 1 -11 1 - -# 7 = Seven -.n 7 6 1 2 3 4 5 6 -0--000 0 ---0--- 0 -1--111 0 --1---- 0 --01-10 1 --0110- 1 -001-1- 1 --01-01 1 --010-1 1 -101-0- 1 -101--0 1 -001--1 1 -001--1 1 -0011-- 1 -1010-- 1 --011-0 1 --0101- 1 - -.e end of file \ No newline at end of file diff --git a/cana/drawing/schema_vis.py b/cana/drawing/schema_vis.py index d6b8a67..82fa142 100644 --- a/cana/drawing/schema_vis.py +++ b/cana/drawing/schema_vis.py @@ -12,9 +12,8 @@ def plot_schemata(n, plotTS=True): k = n.k if n.k >= 1 else 1 outputs = np.array(n.outputs) - if "?" in outputs: # check if there are any '?' in the output. - print("Error (plot_schemata()): The output contains '?'") - return False + if "?" in outputs: # check if there are any '?' in the output. + raise ValueError("Error (plot_schemata()): The output contains '?'") if np.all(outputs[0] == outputs): return False inputs = n.inputs if not n.constant else [n.name] diff --git a/cana/utils.py b/cana/utils.py index 962c216..dcbcd9b 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -328,7 +328,8 @@ def input_monotone(outputs, input_idx, activation=1): return all(monotone_configs) -def fill_out_lut(partial_lut, verbose= False): + +def fill_out_lut(partial_lut, verbose=False): """ Fill out a partial LUT with missing entries. @@ -346,7 +347,6 @@ def fill_out_lut(partial_lut, verbose= False): >>> fill_out_lut([('00', 0), ('01', 0), ('1-', 1), ('11', 1)]) [('00', 0), ('01', 0), ('10', 1), ('11', 1)] - # TODO: [SRI] generate LUT with a specified effective connectivity # TODO: [SRI] generate LUT from two symbol schemata, with a specified ratio of wildcard symbols # TODO: [SRI] add tests for canonical rule logic, rule 90, rule 110 # TODO: [SRI] use examples COSA rule, GKL rule where you fill up LUT based on the annihilation inputs and see if it matches with the rules plus bias. @@ -354,49 +354,58 @@ def fill_out_lut(partial_lut, verbose= False): # Check if all the input entries of the partial LUT are of the same length. if len(set([len(x[0]) for x in partial_lut])) != 1: - raise ValueError('All the input entries of the partial LUT must be of the same length.') + raise ValueError( + "All the input entries of the partial LUT must be of the same length." + ) k = len(partial_lut[0][0]) - all_states = {entry[0]: entry[1] for entry in partial_lut} + all_states = dict(partial_lut) for entry in partial_lut: - if not all([x in ['0','1','-','#','2','x'] for x in entry[0]]): - raise ValueError('All the input entries of the partial LUT must be valid binary strings.') - - elif any([x in ['-', '#','2','x'] for x in entry[0]]): - missing_data_indices = [i for i, x in enumerate(entry[0]) if x == '-'] - table=[] - output_list_permutations=[] + if not all([x in ["0", "1", "-", "#", "2", "x"] for x in entry[0]]): + raise ValueError( + "All the input entries of the partial LUT must be valid binary strings." + ) + + elif any([x in ["-", "#", "2", "x"] for x in entry[0]]): + missing_data_indices = [ + i for i, x in enumerate(entry[0]) if x in ["-", "#", "x"] + ] + table = [] + output_list_permutations = [] for i in range(2 ** len(missing_data_indices)): row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))] table.append(row) output_list_permutations.append(entry[0]) for j in range(len(missing_data_indices)): - output_list_permutations[i] = output_list_permutations[i][:missing_data_indices[j]] + str(table[i][j]) + output_list_permutations[i][missing_data_indices[j]+1:] + output_list_permutations[i] = ( + output_list_permutations[i][: missing_data_indices[j]] + + str(table[i][j]) + + output_list_permutations[i][missing_data_indices[j] + 1 :] + ) del all_states[entry[0]] for perm in output_list_permutations: if perm in all_states and all_states[perm] != entry[1]: - print('Clashing output values for entry:', perm) - all_states[perm] = '!' + print("Clashing output values for entry:", perm) + all_states[perm] = "!" else: all_states[perm] = entry[1] for i in range(2**k): state = bin(i)[2:].zfill(k) if state not in all_states: - all_states[state] = '?' + all_states[state] = "?" if verbose: # Print a statement if there are any missing values '?' in the LUT. Else print a statement that the LUT is complete. - if '?' in all_states.values(): - print('The LUT is incomplete. Missing values are represented by \'?\'') + if "?" in all_states.values(): + print("The LUT is incomplete. Missing values are represented by '?'") else: - print('The LUT is complete.') + print("The LUT is complete.") all_states = sorted(all_states.items(), key=lambda x: x[0]) return all_states - diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index d4a8768..4815842 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -12,33 +12,54 @@ # Test Input Redundancy # + def test_input_redundancy_constant(): """Test Input Redundancy - constant""" n = BooleanNode(k=1, outputs=list("00")) k_r, true_k_r = n.input_redundancy(norm=False), 1 - assert (k_r == true_k_r), ('Input Redundancy (mean) for CONSTANT node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean) for CONSTANT node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), 1 - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for CONSTANT node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for CONSTANT node does not match. %s != %s" + % (k_r, true_k_r) + ) + def test_input_redundancy_identity(): """Test Input Redundancy - identity""" n = BooleanNode(k=1, outputs=list("01")) k_r, true_k_r = n.input_redundancy(norm=False), 0 - assert (k_r == true_k_r), ('Input Redundancy (mean) for identity node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean) for identity node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), 0 - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for identity node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for identity node does not match. %s != %s" + % (k_r, true_k_r) + ) + # AND def test_input_redundancy_AND(): """Test Input Redundancy - AND""" n = AND() k_r, true_k_r = n.input_redundancy(norm=False), (3 / 4) - assert (k_r == true_k_r), ('Input Redundancy (mean) for AND node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean) for AND node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), (3 / 4) / 2 - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for AND node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for AND node does not match. %s != %s" + % (k_r, true_k_r) + ) # OR @@ -46,10 +67,15 @@ def test_input_redundancy_OR(): """Test Input Redundancy - OR""" n = OR() k_r, true_k_r = n.input_redundancy(norm=False), 3 / 4 - assert (k_r == true_k_r), ('Input Redundancy (mean) for OR node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean) for OR node does not match. %s != %s" % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), (3 / 4) / 2 - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for OR node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for OR node does not match. %s != %s" + % (k_r, true_k_r) + ) # XOR @@ -57,32 +83,50 @@ def test_input_redundancy_XOR(): """Test Input Redundancy - XOR""" n = XOR() k_r, true_k_r = n.input_redundancy(norm=False), 0 - assert (k_r == true_k_r), ('Input Redundancy (mean) for XOR node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean) for XOR node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), 0 - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for XOR node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for XOR node does not match. %s != %s" + % (k_r, true_k_r) + ) # CONTRADICTION def test_input_redundancy_CONTRADICTION(): """Test Input Redundancy - CONTRADICTION""" n = CONTRADICTION() - k_r, true_k_r = n.input_redundancy(norm=False), 2. - assert (k_r == true_k_r), ('Input Redundancy (mean) for CONTRADICTION node does not match. %s != %s' % (k_r, true_k_r)) + k_r, true_k_r = n.input_redundancy(norm=False), 2.0 + assert k_r == true_k_r, ( + "Input Redundancy (mean) for CONTRADICTION node does not match. %s != %s" + % (k_r, true_k_r) + ) - k_r, true_k_r = n.input_redundancy(norm=True), 1. - assert (k_r == true_k_r), ('Input Redundancy (mean, normed) for CONTRADICTION node does not match. %s != %s' % (k_r, true_k_r)) + k_r, true_k_r = n.input_redundancy(norm=True), 1.0 + assert k_r == true_k_r, ( + "Input Redundancy (mean, normed) for CONTRADICTION node does not match. %s != %s" + % (k_r, true_k_r) + ) # COPYx1 def test_input_redundancy_COPYx1(): """Test Input Redundancy - COPYx1""" n = COPYx1() - k_r, true_k_r = n.input_redundancy(norm=False), 1. - assert (k_r == true_k_r), ('Input Redundancy (upper) for COPYx1 node does not match. %s != %s' % (k_r, true_k_r)) + k_r, true_k_r = n.input_redundancy(norm=False), 1.0 + assert k_r == true_k_r, ( + "Input Redundancy (upper) for COPYx1 node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), 1 / 2 - assert (k_r == true_k_r), ('Input Redundancy (upper, normed) for COPYx1 node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (upper, normed) for COPYx1 node does not match. %s != %s" + % (k_r, true_k_r) + ) # RULE 90 @@ -90,10 +134,16 @@ def test_input_redundancy_RULE90(): """Test Input Redundancy - RULE90""" n = RULE90() k_r, true_k_r = n.input_redundancy(norm=False), 8 / 8 - assert (k_r == true_k_r), ('Input Redundancy (upper) for RULE90 node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (upper) for RULE90 node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), (8 / 8) / 3 - assert (k_r == true_k_r), ('Input Redundancy (upper, normed) for RULE90 node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (upper, normed) for RULE90 node does not match. %s != %s" + % (k_r, true_k_r) + ) # RULE 110 @@ -101,145 +151,255 @@ def test_input_redundancy_RULE110(): """Test Input Redundancy - RULE110""" n = RULE110() k_r, true_k_r = n.input_redundancy(norm=False), 7 / 8 - assert (k_r == true_k_r), ('Input Redundancy (upper) for RULE110 node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (upper) for RULE110 node does not match. %s != %s" + % (k_r, true_k_r) + ) k_r, true_k_r = n.input_redundancy(norm=True), (7 / 8) / 3 - assert (k_r == true_k_r), ('Input Redundancy (upper, normed) for RULE110 node does not match. %s != %s' % (k_r, true_k_r)) + assert k_r == true_k_r, ( + "Input Redundancy (upper, normed) for RULE110 node does not match. %s != %s" + % (k_r, true_k_r) + ) # # Test Edge Redundancy # + # AND def test_edge_redundancy_AND(): """Test Edge Redundancy - AND""" n = AND() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [1 / 2., 1 / 2] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for AND node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [3 / 8., 3 / 8] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for AND node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [1 / 4., 1 / 4] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for AND node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [1 / 2.0, 1 / 2] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for AND node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [3 / 8.0, 3 / 8] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for AND node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [1 / 4.0, 1 / 4] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for AND node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.25, 0.5), (0.25, 0.5)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for AND node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="tuple"), [(0.25, 0.5), (0.25, 0.5)] + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for AND node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # OR def test_edge_redundancy_OR(): """Test Edge Redundancy - OR""" n = OR() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [1 / 2., 1 / 2] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for OR node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [3 / 8., 3 / 8] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for OR node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [1 / 4., 1 / 4] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for OR node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.25, 0.5), (0.25, 0.5)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for OR node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [1 / 2.0, 1 / 2] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for OR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [3 / 8.0, 3 / 8] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for OR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [1 / 4.0, 1 / 4] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for OR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = n.edge_redundancy(bound="tuple"), [(0.25, 0.5), (0.25, 0.5)] + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for OR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # XOR def test_edge_redundancy_XOR(): """Test Edge Redundancy - XOR""" n = XOR() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [0, 0] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for XOR node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [0, 0] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for XOR node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [0, 0] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for XOR node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.0, 0.0), (0.0, 0.0)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for XOR node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [0, 0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for XOR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [0, 0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for XOR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [0, 0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for XOR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = n.edge_redundancy(bound="tuple"), [(0.0, 0.0), (0.0, 0.0)] + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for XOR node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # CONTRADICTION def test_edge_redundancy_CONTRADICTION(): """Test Edge Redundancy - CONTRADICTION""" n = CONTRADICTION() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [1., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for CONTRADICTION node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [1., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for CONTRADICTION node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [1., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for CONTRADICTION node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(1.0, 1.0), (1.0, 1.0)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for CONTRADICTION node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [1.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for CONTRADICTION node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [1.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for CONTRADICTION node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [1.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for CONTRADICTION node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = n.edge_redundancy(bound="tuple"), [(1.0, 1.0), (1.0, 1.0)] + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for CONTRADICTION node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # COPYx1 def test_edge_redundancy_COPYx1(): """Test Edge Redundancy - COPYx1""" n = COPYx1() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [0., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for COPYx1 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [0., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for COPYx1 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [0., 1.] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for COPYx1 node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.0, 0.0), (1.0, 1.0)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for COPYx1 node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [0.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for COPYx1 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [0.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for COPYx1 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [0.0, 1.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for COPYx1 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = n.edge_redundancy(bound="tuple"), [(0.0, 0.0), (1.0, 1.0)] + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for COPYx1 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # RULE 90 def test_edge_redundancy_RULE90(): """Test Edge Redundancy - RULE90""" n = RULE90() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [0., 1., 0.] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper bound) for RULE90 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [0., 1., 0.] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for RULE90 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [0., 1., 0.] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower bound) for RULE90 node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.0, 0.0), (1.0, 1.0), (0.0, 0.0)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for RULE90 node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [0.0, 1.0, 0.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper bound) for RULE90 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [0.0, 1.0, 0.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for RULE90 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [0.0, 1.0, 0.0] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower bound) for RULE90 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = ( + n.edge_redundancy(bound="tuple"), + [(0.0, 0.0), (1.0, 1.0), (0.0, 0.0)], + ) + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for RULE90 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # RULE 110 def test_edge_redundancy_RULE110(): """Test Edge Redundancy - RULE110""" n = RULE110() - r_ji, true_r_ji = n.edge_redundancy(bound='upper'), [6 / 8, 2 / 8, 2 / 8] - assert (r_ji == true_r_ji), ('Edge Redundancy (upper) for RULE110 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='mean'), [5 / 8, 1 / 8, 1 / 8] - assert (r_ji == true_r_ji), ('Edge Redundancy (mean) for RULE110 node does not match. %s != %s' % (r_ji, true_r_ji)) - r_ji, true_r_ji = n.edge_redundancy(bound='lower'), [4 / 8., 0 / 8, 0 / 8] - assert (r_ji == true_r_ji), ('Edge Redundancy (lower) for RULE110 node does not match. %s != %s' % (r_ji, true_r_ji)) - - r_ji, true_r_ji = n.edge_redundancy(bound='tuple'), [(0.5, 0.75), (0.0, 0.25), (0.0, 0.25)] - assert (r_ji == true_r_ji), ('Edge Redundancy (tuples) for RULE110 node does not match. %s != %s' % (r_ji, true_r_ji)) + r_ji, true_r_ji = n.edge_redundancy(bound="upper"), [6 / 8, 2 / 8, 2 / 8] + assert r_ji == true_r_ji, ( + "Edge Redundancy (upper) for RULE110 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="mean"), [5 / 8, 1 / 8, 1 / 8] + assert r_ji == true_r_ji, ( + "Edge Redundancy (mean) for RULE110 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + r_ji, true_r_ji = n.edge_redundancy(bound="lower"), [4 / 8.0, 0 / 8, 0 / 8] + assert r_ji == true_r_ji, ( + "Edge Redundancy (lower) for RULE110 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) + + r_ji, true_r_ji = ( + n.edge_redundancy(bound="tuple"), + [(0.5, 0.75), (0.0, 0.25), (0.0, 0.25)], + ) + assert r_ji == true_r_ji, ( + "Edge Redundancy (tuples) for RULE110 node does not match. %s != %s" + % (r_ji, true_r_ji) + ) # # Test Effective Connectivity # + # AND def test_effective_connectivity_AND(): """Test Effective Connectivity - AND""" n = AND() k_e, true_k_e = n.effective_connectivity(norm=False), 5 / 4 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for AND node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for AND node does not match. %s != %s" + % (k_e, true_k_e) + ) k_e, true_k_e = n.effective_connectivity(norm=True), (5 / 4) / 2 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for AND node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for AND node does not match. %s != %s" + % (k_e, true_k_e) + ) # XOR def test_effective_connectivity_XOR(): """Test Effective Connectivity - XOR""" n = XOR() - k_e, true_k_e = n.effective_connectivity(norm=False), 2. - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for XOR node does not match. %s != %s' % (k_e, true_k_e)) + k_e, true_k_e = n.effective_connectivity(norm=False), 2.0 + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for XOR node does not match. %s != %s" + % (k_e, true_k_e) + ) - k_e, true_k_e = n.effective_connectivity(norm=True), 2. / 2 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for XOR node does not match. %s != %s' % (k_e, true_k_e)) + k_e, true_k_e = n.effective_connectivity(norm=True), 2.0 / 2 + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for XOR node does not match. %s != %s" + % (k_e, true_k_e) + ) # CONTRADICTION @@ -247,10 +407,16 @@ def test_effective_connectivity_CONTRADICTION(): """Test Effective Connectivity - CONTRADICTION""" n = CONTRADICTION() k_e, true_k_e = n.effective_connectivity(norm=False), 0 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for CONTRADICTION node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for CONTRADICTION node does not match. %s != %s" + % (k_e, true_k_e) + ) k_e, true_k_e = n.effective_connectivity(norm=True), 0 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for CONTRADICTION node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for CONTRADICTION node does not match. %s != %s" + % (k_e, true_k_e) + ) # COPYx1 @@ -258,10 +424,16 @@ def test_effective_connectivity_COPYx1(): """Test Effective Connectivity - COPYx1""" n = COPYx1() k_e, true_k_e = n.effective_connectivity(norm=False), 1 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for COPYx1 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for COPYx1 node does not match. %s != %s" + % (k_e, true_k_e) + ) k_e, true_k_e = n.effective_connectivity(norm=True), 1 / 2 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for COPYx1 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for COPYx1 node does not match. %s != %s" + % (k_e, true_k_e) + ) # RULE90 @@ -269,10 +441,16 @@ def test_effective_connectivity_RULE90(): """Test Effective Connectivity - RULE90""" n = RULE90() k_e, true_k_e = n.effective_connectivity(norm=False), 3 - 1 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for RULE90 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for RULE90 node does not match. %s != %s" + % (k_e, true_k_e) + ) k_e, true_k_e = n.effective_connectivity(norm=True), (3 - 1) / 3 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for RULE90 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for RULE90 node does not match. %s != %s" + % (k_e, true_k_e) + ) # RULE110 @@ -280,86 +458,148 @@ def test_effective_connectivity_RULE110(): """Test Effective Connectivity - RULE110""" n = RULE110() k_e, true_k_e = n.effective_connectivity(norm=False), 3 - (7 / 8) - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound) for RULE110 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound) for RULE110 node does not match. %s != %s" + % (k_e, true_k_e) + ) k_e, true_k_e = n.effective_connectivity(norm=True), (3 - (7 / 8)) / 3 - assert (k_e == true_k_e), ('Effective Connectivity (node,upper bound,normed) for RULE110 node does not match. %s != %s' % (k_e, true_k_e)) + assert k_e == true_k_e, ( + "Effective Connectivity (node,upper bound,normed) for RULE110 node does not match. %s != %s" + % (k_e, true_k_e) + ) # # Test Edge Effectiveness # + # AND def test_edge_effectiveness_AND(): """Test Edge Effectiveness - AND""" n = AND() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [1 - (2 / 4), 1 - (2 / 4)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for AND node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [1 - (3 / 8), 1 - (3 / 8)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for AND node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [1 - (1 / 4), 1 - (1 / 4)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for AND node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [1 - (2 / 4), 1 - (2 / 4)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for AND node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [1 - (3 / 8), 1 - (3 / 8)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for AND node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [1 - (1 / 4), 1 - (1 / 4)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for AND node does not match. %s != %s" + % (e_ji, true_e_ji) + ) # XOR def test_edge_effectiveness_XOR(): """Test Edge Effectiveness - XOR""" n = XOR() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [1 - (0), 1 - (0)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for XOR node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [1 - (0), 1 - (0)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for XOR node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [1 - (0), 1 - (0)] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for XOR node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [1 - (0), 1 - (0)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for XOR node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [1 - (0), 1 - (0)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for XOR node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [1 - (0), 1 - (0)] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for XOR node does not match. %s != %s" + % (e_ji, true_e_ji) + ) # CONTRADICTION def test_edge_effectiveness_CONTRADICTION(): """Test Edge Effectiveness - CONTRADICTION""" n = CONTRADICTION() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [0, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for CONTRADICTION node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [0, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for CONTRADICTION node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [0, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for CONTRADICTION node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [0, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for CONTRADICTION node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [0, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for CONTRADICTION node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [0, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for CONTRADICTION node does not match. %s != %s" + % (e_ji, true_e_ji) + ) # COPYx1 def test_edge_effectiveness_COPYx1(): """Test Edge Effectiveness - COPYx1""" n = COPYx1() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [1, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for COPYx1 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [1, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for COPYx1 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [1, 0] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for COPYx1 node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [1, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for COPYx1 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [1, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for COPYx1 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [1, 0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for COPYx1 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) # RULE90 def test_edge_effectiveness_RULE90(): """Test Edge Effectiveness - RULE90""" n = RULE90() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [1, 0, 1] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for RULE90 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [1, 0, 1] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for RULE90 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [1, 0, 1] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for RULE90 node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [1, 0, 1] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for RULE90 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [1, 0, 1] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for RULE90 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [1, 0, 1] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for RULE90 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) # RULE110 def test_edge_effectiveness_RULE110(): """Test Edge Effectiveness - RULE110""" n = RULE110() - e_ji, true_e_ji = n.edge_effectiveness(bound='upper'), [0.25, 0.75, 0.75] - assert (e_ji == true_e_ji), ('Input Redundancy (input,upper bound) for RULE110 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='mean'), [0.375, 0.875, 0.875] - assert (e_ji == true_e_ji), ('Input Redundancy (input,mean) for RULE110 node does not match. %s != %s' % (e_ji, true_e_ji)) - e_ji, true_e_ji = n.edge_effectiveness(bound='lower'), [0.5, 1., 1.] - assert (e_ji == true_e_ji), ('Input Redundancy (input,lower bound) for RULE110 node does not match. %s != %s' % (e_ji, true_e_ji)) + e_ji, true_e_ji = n.edge_effectiveness(bound="upper"), [0.25, 0.75, 0.75] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,upper bound) for RULE110 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="mean"), [0.375, 0.875, 0.875] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,mean) for RULE110 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + e_ji, true_e_ji = n.edge_effectiveness(bound="lower"), [0.5, 1.0, 1.0] + assert e_ji == true_e_ji, ( + "Input Redundancy (input,lower bound) for RULE110 node does not match. %s != %s" + % (e_ji, true_e_ji) + ) + # # Test Sensitivity @@ -368,50 +608,84 @@ def test_sensitivity_AND(): """Test Sensitivity - AND""" n = AND() s, true_s = n.c_sensitivity(1), 1 / 2 - assert isclose(s, true_s), ('c-sensitivity(1) for AND does not match, %s != %s' % (s, true_s)) + assert isclose(s, true_s), "c-sensitivity(1) for AND does not match, %s != %s" % ( + s, + true_s, + ) s, true_s = n.c_sensitivity(2), 1 / 2 - assert isclose(s, true_s), ('c-sensitivity(2) for AND does not match, %s != %s' % (s, true_s)) - s, true_s = n.c_sensitivity(1, 'forceK', 3), 1 / 3 - assert isclose(s, true_s), ("c-sensitivity(1,'forceK',3) for AND does not match, %s != %s" % (s, true_s)) - s, true_s = n.c_sensitivity(2, 'forceK', 3), 1 / 2 - assert isclose(s, true_s), ("c-sensitivity(2,'forceK',3) for AND does not match, %s != %s" % (s, true_s)) + assert isclose(s, true_s), "c-sensitivity(2) for AND does not match, %s != %s" % ( + s, + true_s, + ) + s, true_s = n.c_sensitivity(1, "forceK", 3), 1 / 3 + assert isclose(s, true_s), ( + "c-sensitivity(1,'forceK',3) for AND does not match, %s != %s" % (s, true_s) + ) + s, true_s = n.c_sensitivity(2, "forceK", 3), 1 / 2 + assert isclose(s, true_s), ( + "c-sensitivity(2,'forceK',3) for AND does not match, %s != %s" % (s, true_s) + ) def test_sensitivity_XOR(): """Test Sensitivity - XOR""" n = XOR() - s, true_s = n.c_sensitivity(1), 1. - assert isclose(s, true_s), ('c-sensitivity(1) for XOR does not match, %s != %s' % (s, true_s)) - s, true_s = n.c_sensitivity(2), 0. - assert isclose(s, true_s), ('c-sensitivity(2) for XOR does not match, %s != %s' % (s, true_s)) - s, true_s = n.c_sensitivity(1, 'forceK', 3), 2 / 3 - assert isclose(s, true_s), ("c-sensitivity(1,'forceK',3) for XOR does not match, %s != %s" % (s, true_s)) - s, true_s = n.c_sensitivity(2, 'forceK', 3), 2 / 3 - assert isclose(s, true_s), ("c-sensitivity(2,'forceK',3) for XOR does not match, %s != %s" % (s, true_s)) + s, true_s = n.c_sensitivity(1), 1.0 + assert isclose(s, true_s), "c-sensitivity(1) for XOR does not match, %s != %s" % ( + s, + true_s, + ) + s, true_s = n.c_sensitivity(2), 0.0 + assert isclose(s, true_s), "c-sensitivity(2) for XOR does not match, %s != %s" % ( + s, + true_s, + ) + s, true_s = n.c_sensitivity(1, "forceK", 3), 2 / 3 + assert isclose(s, true_s), ( + "c-sensitivity(1,'forceK',3) for XOR does not match, %s != %s" % (s, true_s) + ) + s, true_s = n.c_sensitivity(2, "forceK", 3), 2 / 3 + assert isclose(s, true_s), ( + "c-sensitivity(2,'forceK',3) for XOR does not match, %s != %s" % (s, true_s) + ) + # input symmetry tests (new) def test_input_symmetry_AND(): n = AND() - k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 3.0/2 - assert (k_s == true_k_s), f"Input symmetry: AND (mean): returned {k_s}, true value is {true_k_s}" - k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots"), 3.0/2 - assert (k_s == true_k_s), f"Input symmetry: AND (max): returned {k_s}, true value is {true_k_s}" - k_s, true_k_s = n.input_symmetry_mean(), 3.0/2 - assert (k_s == true_k_s), f"Input symmetry simp: AND (mean): returned {k_s}, true value is {true_k_s}" + k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 3.0 / 2 + assert ( + k_s == true_k_s + ), f"Input symmetry: AND (mean): returned {k_s}, true value is {true_k_s}" + k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots"), 3.0 / 2 + assert ( + k_s == true_k_s + ), f"Input symmetry: AND (max): returned {k_s}, true value is {true_k_s}" + k_s, true_k_s = n.input_symmetry_mean(), 3.0 / 2 + assert ( + k_s == true_k_s + ), f"Input symmetry simp: AND (mean): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: AND (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: AND (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + def test_input_symmetry_XOR(): n = XOR() k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 1.0 - assert (k_s == true_k_s), f"Input symmetry: XOR (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: XOR (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry_mean(), 1.0 - assert (k_s == true_k_s), f"Input symmetry simp: XOR (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry simp: XOR (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots"), 1.0 - assert (k_s == true_k_s), f"Input symmetry: XOR (max): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: XOR (max): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: XOR (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" @@ -420,14 +694,21 @@ def test_input_symmetry_XOR(): # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: XOR (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + def test_input_symmetry_COPYx1(): n = COPYx1() k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 0 - assert (k_s == true_k_s), f"Input symmetry: COPYx1 (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: COPYx1 (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry_mean(), 0 - assert (k_s == true_k_s), f"Input symmetry simp: COPYx1 (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry simp: COPYx1 (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots"), 0 - assert (k_s == true_k_s), f"Input symmetry: COPYx1 (max): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: COPYx1 (max): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots", sameSymbol=True), 0.0 # assert (k_s == true_k_s), f"Input symmetry: COPYx1 (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" @@ -436,14 +717,21 @@ def test_input_symmetry_COPYx1(): # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 0.0 # assert (k_s == true_k_s), f"Input symmetry: COPYx1 (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + def test_input_symmetry_RULE90(): n = RULE90() k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 1.0 - assert (k_s == true_k_s), f"Input symmetry: RULE90 (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: RULE90 (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry_mean(), 1.0 - assert (k_s == true_k_s), f"Input symmetry simp: RULE90 (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry simp: RULE90 (mean): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 1.0 - assert (k_s == true_k_s), f"Input symmetry: RULE90 (max): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: RULE90 (max): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: RULE90 (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" @@ -452,14 +740,21 @@ def test_input_symmetry_RULE90(): # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 2.0 # assert (k_s == true_k_s), f"Input symmetry: RULE90 (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + def test_input_symmetry_SBF(): - n = BooleanNode(outputs=list("0111" + "0"*12), k=4) + n = BooleanNode(outputs=list("0111" + "0" * 12), k=4) k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots"), 1.6875 - assert (k_s == true_k_s), f"Input symmetry: SBF (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: SBF (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry_mean(), 1.6875 - assert (k_s == true_k_s), f"Input symmetry simp: SBF (mean): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry simp: SBF (mean): returned {k_s}, true value is {true_k_s}" k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots"), 1.875 - assert (k_s == true_k_s), f"Input symmetry: SBF (max): returned {k_s}, true value is {true_k_s}" + assert ( + k_s == true_k_s + ), f"Input symmetry: SBF (max): returned {k_s}, true value is {true_k_s}" # k_s, true_k_s = n.input_symmetry(aggOp="mean", kernel="numDots", sameSymbol=True), 4.0 # assert (k_s == true_k_s), f"Input symmetry: SBF (mean, sameSymbol): returned {k_s}, true value is {true_k_s}" @@ -468,21 +763,85 @@ def test_input_symmetry_SBF(): # k_s, true_k_s = n.input_symmetry(aggOp="max", kernel="numDots", sameSymbol=True), 4.0 # assert (k_s == true_k_s), f"Input symmetry: SBF (max, sameSymbol): returned {k_s}, true value is {true_k_s}" + # Tests for partially-specified functions -def test_partial_lut(): +def test_fill_out_lut(): partial_lut = [ - [('00','1'),('01','1')], - [('0-','1'),('10','1')], - [('001','1'),('01-','1'),('1-1','0')], - [('00--', '0'), ('1--1','1'), ('11--','0')], # Checking for Contradictory values. Should be marked with '!'. + [("00", "1"), ("01", "1")], + [("0-", "1"), ("10", "1")], + [("001", "1"), ("01-", "1"), ("1-1", "0")], + [ + ("00--", "0"), + ("1--1", "1"), + ("11--", "0"), + ], # Checking for Contradictory values. Should be marked with '!'. ] expected_filled = [ - [('00','1'),('01','1'),('10','?'),('11','?')], - [('00','1'),('01','1'),('10','1'),('11','?')], - [('000','?'),('001','1'),('010','1'),('011','1'),('100','?'),('101','0'),('110','?'),('111','0')], - [('0000', '0'), ('0001', '0'), ('0010', '0'), ('0011', '0'), ('0100', '?'), ('0101', '?'), ('0110', '?'), ('0111', '?'), ('1000', '?'), ('1001', '1'), ('1010', '?'), ('1011', '1'), ('1100', '0'), ('1101', '!'),('1110', '0'), ('1111', '!')] + [("00", "1"), ("01", "1"), ("10", "?"), ("11", "?")], + [("00", "1"), ("01", "1"), ("10", "1"), ("11", "?")], + [ + ("000", "?"), + ("001", "1"), + ("010", "1"), + ("011", "1"), + ("100", "?"), + ("101", "0"), + ("110", "?"), + ("111", "0"), + ], + [ + ("0000", "0"), + ("0001", "0"), + ("0010", "0"), + ("0011", "0"), + ("0100", "?"), + ("0101", "?"), + ("0110", "?"), + ("0111", "?"), + ("1000", "?"), + ("1001", "1"), + ("1010", "?"), + ("1011", "1"), + ("1100", "0"), + ("1101", "!"), + ("1110", "0"), + ("1111", "!"), + ], ] for i, partial in enumerate(partial_lut): filled = fill_out_lut(partial) expected = expected_filled[i] - assert(filled==expected), f"Partial LUT filling failed: {filled} != {expected}" \ No newline at end of file + assert ( + filled == expected + ), f"Fill out LUT filling failed: {filled} != {expected}" + + +def test_from_partial_lut(): + partial_luts = [ + [("001-", "0"), ("1--1", "1"), ("11--", "1")], + [("00--", "0"), ("1--1", "1"), ("110-", "1")], + [("1--", "1"), ("101", "0"), ("011", "0"), ("01-", "1")], # will have clashes + [("0--0", "0"), ("1--1", "0"), ("0111", "1"), ("0011", "1")], + [("1-01", "1"), ("1-1-", "0"), ("0110", "0"), ("01-1", "1")], + [("1-01", "1"), ("1-1-", "0"), ("0110", "0"), ("01-1", "?")], + [("-1--", "?")], + ] + expected_output_lists = [ + ['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1'], + ['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1'], + ['?', '?', '1', '!', '1', '!', '1', '1'], + ['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0'], + ['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0'], + ['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0'], + ['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?'], + ] + + for i, partial_lut in enumerate(partial_luts): + generated_node = BooleanNode.from_partial_lut(partial_lut) + expected_output_list = expected_output_lists[i] + + assert ( + generated_node.outputs == expected_output_list + ), f"from_partial_lut failed: {generated_node.outputs} != {expected_output_list}" + + diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index fa6562b..340fcf9 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -10,18 +10,139 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ - "from cana.datasets.bio import PARTIAL_LUTS_DEMO\n", "from cana.drawing.schema_vis import plot_schemata\n", "from cana.drawing.plot_look_up_table import plot_look_up_table\n", "from cana.utils import fill_out_lut\n", "\n", + "from cana.boolean_network import BooleanNetwork\n", "from cana.boolean_node import BooleanNode" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
In:Out:
000000000
100000010
200000100
300000110
400001000
.........
12311110111
12411111001
12511111011
12611111101
12711111111
\n", + "

128 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " In: Out:\n", + "0 0000000 0\n", + "1 0000001 0\n", + "2 0000010 0\n", + "3 0000011 0\n", + "4 0000100 0\n", + ".. ... ...\n", + "123 1111011 1\n", + "124 1111100 1\n", + "125 1111101 1\n", + "126 1111110 1\n", + "127 1111111 1\n", + "\n", + "[128 rows x 2 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from cana.datasets.bio import THALIANA\n", + "\n", + "thaliana = THALIANA()\n", + "\n", + "thaliana.nodes[0].look_up_table()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -37,31 +158,31 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 9, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Clashing output values for entry: 101\n", - "Clashing output values for entry: 011\n" - ] - }, { "data": { "text/plain": [ - "[('000', '?'),\n", - " ('001', '?'),\n", - " ('010', '1'),\n", - " ('011', '!'),\n", - " ('100', '1'),\n", - " ('101', '!'),\n", - " ('110', '1'),\n", - " ('111', '1')]" + "[('0000', '?'),\n", + " ('0001', '?'),\n", + " ('0010', '?'),\n", + " ('0011', '?'),\n", + " ('0100', '?'),\n", + " ('0101', '?'),\n", + " ('0110', '?'),\n", + " ('0111', '?'),\n", + " ('1000', '0'),\n", + " ('1001', '0'),\n", + " ('1010', '0'),\n", + " ('1011', '0'),\n", + " ('1100', '0'),\n", + " ('1101', '0'),\n", + " ('1110', '0'),\n", + " ('1111', '0')]" ] }, - "execution_count": 2, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -73,8 +194,9 @@ " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1---\", \"0\")],\n", "]\n", - "generated_lut = fill_out_lut(partial_luts[1])\n", + "generated_lut = fill_out_lut(partial_luts[3])\n", "generated_lut" ] }, @@ -93,92 +215,49 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Entry clash in node 5 for {'000'} i.e. State number: 0\n", - "\n", + "\n", " In: Out:\n", - "0 00 0\n", - "1 01 1\n", + "0 00 1\n", + "1 01 ?\n", "2 10 ?\n", - "3 11 1\n", - "Error (schemata_look_up_table): The outputs contain missing values. Please fill the missing values before generating the schemata look-up table.\n", - "False\n" + "3 11 ?\n" ] }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Error (plot_schemata()): The output contains '?'\n" - ] - }, - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "partial_luts = (\n", - " PARTIAL_LUTS_DEMO()\n", - ") # Instantiating a sample partial_luts dataset from the dataset folder.\n", + "partial_luts_network = BooleanNetwork.from_file(\n", + " \"partial_LUT_demo_nodes.txt\",\n", + " name=\"Partial LUTs Demo\",\n", + " keep_constants=True,\n", + " partial_lut=True,\n", + ")\n", + "\n", "\n", - "node = partial_luts.nodes[5]\n", + "node = partial_luts_network.nodes[2]\n", "\n", "print(node)\n", "print(node.look_up_table())\n", - "print(node.schemata_look_up_table()) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table.\n", + "# print(node.schemata_look_up_table()) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table.\n", "\n", "plot_look_up_table(node)\n", - "plot_schemata(node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Warning: There is a '?' value in the output. It will be treated as zero for the bias calculation.\n" - ] - }, - { - "data": { - "text/plain": [ - "0.5" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "node.bias()" + "# plot_schemata(node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." ] }, { @@ -192,53 +271,36 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Error (plot_schemata()): The output contains '?'\n" + "['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1']\n", + "Clashing output values for entry: 101\n", + "Clashing output values for entry: 011\n", + "['?', '?', '1', '!', '1', '!', '1', '1']\n", + "['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0']\n", + "['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?']\n" ] - }, - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ "partial_luts = [\n", - " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", - " \n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"-1--\", \"?\")],\n", "]\n", - "partial_lut = partial_luts[3]\n", + "partial_lut = partial_luts[6]\n", "\n", "\"\"\"\n", "generated_lut = fill_out_lut(partial_lut) # Using the fill_out_lut function found in utils.py\n", @@ -247,13 +309,37 @@ "generated_node = BooleanNode.from_output_list(output_list) # Instantiating a BooleanNode object from the output_list\n", "generated_node.look_up_table() # Displaying the look-up table of the generated_node\n", "\"\"\"\n", + "for partial_lut in partial_luts:\n", + " # Combining the above functions into a single function under BooleanNode class\n", + " generated_node = BooleanNode.from_partial_lut(partial_lut)\n", + " # print(generated_node)\n", + " print(generated_node.outputs)\n", + " # plot_look_up_table(generated_node)\n", + " # plot_schemata(generated_node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "['1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0']\n" + ] + } + ], + "source": [ + "# filling missing output values randomly with 1 or 0 instead of '?'\n", "\n", - "# Combining the above functions into a single function under BooleanNode class\n", - "generated_node = BooleanNode.from_partial_lut(partial_lut) \n", + "generated_node = BooleanNode.from_partial_lut(\n", + " partial_lut, fill_missing_output_randomly=True\n", + ")\n", "print(generated_node)\n", - "# print(generated_node.outputs)\n", - "plot_look_up_table(generated_node)\n", - "plot_schemata(generated_node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." + "print(generated_node.outputs)" ] }, { @@ -271,91 +357,68 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Generated the node with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "\n" + "The LUT is incomplete. Missing values are represented by '?'.\n", + "['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", + "Generated 8 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", + "['1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0']\n", + "['0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", + "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", + "['1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '0', '0', '0']\n", + "['1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0']\n", + "['1', '1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0']\n", + "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n" ] - }, - { - "data": { - "image/png": "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GFq2bBk8PT2xZcsWhaNT3m9+8xt89913bXqPTz75BPfdd5/9/Yzg6aefxiOPPIIVK1bYR4Ci+n7961+36nU9evTAwYMHFY6GiIioZUySXn7WJSIiIiIip+DlRkREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEiGRQIREREREcmwSCAiIiIiIhkWCUREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZHgRP3790f//v21DsMpRGorwPZSy3D9ERGRq2ORQEREREREMiwSiIiIiIhIhkUCERERERHJsEggIiIiIiIZFglERERERCTDIoGIiIiIiGRMkiRJWgfhbDExMTh06JDWYRBRC1ksFnz66acwmUxtfi9JkvCLX/xCuFxgsViQlZWldRhEROTihCwSlPiCQUTaKCsrg9lsbvP7WK1W+Pn5KRCR/giY9omIqIU8tA5AS3v37oWPj4/WYajq8uXLiI+PBwAUFxcr8uXKVZWUlKBXr15ah6EJo/flGzduYPjw4aq9v9H3DaC2KAoJCdE6DCIi0gmhiwQfHx9Df7ECIGuf2Ww29BchI7ftdkToy2oy+r5BRETUUrxxmYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEiGRQIREREREcmwSCAiIiIiIhkWCUREREREJMMigYiIiIiIZFgkEBERERGRDIsEIiIiIiKSYZFAREREREQyLBKIiIiIiEhG0yJh9OjRmDlzppYhEBERERFRHZoVCVeuXMGuXbvg6empVQhERERERNQAzYqEzMxM1NTUICEhQasQiIiIiIioAZoVCQcOHMCQIUMQHh6uVQhERERERNQAzYqEgwcP4umnn9bq44mIiIiIqBGaFAmlpaU4c+YMxo8fr8XHExERERFRE1QvEgoLCzF79mwMGDAA/v7+cHNzQ1BQEKqrq9G+fXu1P95lTJ8+HdHR0Xj55Zdl0w8cOIDo6GhER0ejqKhIo+iUU1lZiTVr1uCBBx5AcHAwfH190adPH8ycOROnT5/WOjxVRERE4KuvvoIkScjIyNA6HNWJ0pfVIOL+QURE+uSh5ptnZWXhkUcegdVqrTdv6NChan60S6mqqkJeXh4AYPDgwbJ5R44cAQB06dIFd955p9NjU1JRUREeffRR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6RUVFfY2GeW0s42e+rKrjXRho6d12BJtzflGYtRt3BTmfOZ8o/RlpRllHSr6bdy2M7V2h1m7di0A4De/+Y1iMWmpa9euOHz4MNLS0rBp0yZs2rQJVqsV3bp1w/Tp0zFr1iz07dtX6zAV8+qrr6Jnz571poeGhmLJkiX2///444+6PWDYvhRFRETIitljx46hqqoKQP1T0kagl75sG+kiMTERhYWFGDNmjOYjXdjoZR22RFtzvtEYcRs3hTmfOZ8aZ4R1aJIkSdI6CADYunUrfve736F79+44duyYqg+VMJlMAICysjKXPcWjlJKSEpe8Y15tn376KXx8fLQOQ1WXL1/G8OHDARi/L1utVvj5+QFQrq1qvKcrc2yvlmn/xIkTiIiIwC9/+UscOHDAKZ9p+6Vu69at8Pb2dspnaqW0tBQTJ04EUPsLvu3GWiPy9PS058D58+fbr0YwqrKyMnvxZfS+XFFRYT8LrFRb1XhPV+bY3h07drTqPVziAtFPPvkEEydOREBAALZv3+6ST50jIiIiIhKF5kVCeno64uPj4e/vj/379xvytB0RERERkZ5oWiS8//77GDt2LO644w4cOHCABQIRERERkQvQrEhYu3YtnnzySdx5553IzMxE//79tQqFiIiIiIgcaFIkvP3225g2bRruuusuZGZm4u6779YiDCIiIiIiaoDTH0jw7rvv4qWXXgIAxMbGYv369fWWCQwMxB//+EcnR0ZERGrYvn07tm/fDqB29B2g9iFVkyZNsi+zYcMGp8dFRESNc3qRUFhYaP/b9lyEun72s5+xSCAiMoijR4/iH//4h2xacXGxbBqLBCIi1+L0y42SkpIgSVKT/86ePevssIiISCXNyftERORaNB8ClYiIiIiIXAuLBCIiIiIikmGRQEREREREMiwSiIiIiIhIhkUCERERERHJOH0IVFditVq1DkF1IrSxITdu3NA6BNU5ttHo21nt9hl9/QFitPF2KioqtA5BdY5tdHd31zAS9Tm279atWxpG4hyObTR6X1a7fUZff4AybTRJAo49ZzKZtA6BiFqprKwMZrO5ze9jtVrh5+enQET6I1raj4uL0zoEImqlrVu3wtvbu83vU1FRgXHjxikQkf7s2LGjVa8T8nIji8WidQhE1AoWiwW+vr6KvJevr6+QuUDENoeFhWkdAhG1QlhYGLy8vBR5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OSNtW0Dc7asGI+R8xTKzrfpsboW5fPlylJaW4vr168jLy8P+/fvRo0cPLFu2TKmQNLN06dIGp993333Izs52cjTqEqmtjpoa99io2rVrh8TERCQmJmodSqNccaQLR3pYhy3R0rxfl21Uld/85jeKxaQlEfICc76xibp91aL3nK9YkVBSUtKi5ZcvX47/+7//s/9/yJAheO+993D33XcrFRIRCcg20gWpr6V539HWrVuRlpaGHj16GOJeNCIio1F0CNSWOHv2LCRJwsWLF/Hxxx9DkiQMHjwYO3bs0CokIiJygk8++QQTJ05EQEAAtm/fjsDAQK1DIiKiOjQrEmw6duyIhx9+GHv37oWvry+eeuopXL16VeuwiIhIBenp6YiPj4e/vz/279/P65uJiFyU5kWCTWBgIO6//36Ulpbar3MlIiLjeP/99zF27FjccccdOHDgAAsEIiIX5jJFAgCcP38eQO2NHkREZBxr167Fk08+iTvvvBOZmZno37+/1iEREVETnFoknD59utFLiVauXIns7GyEhITg3nvvdWZYRESkorfffhvTpk3DXXfdhczMTA5QQUSkA04dnHr37t2YN28efv7zn6NXr17o1KkTLl68iM8++wwnT56E2WzGe++9Zx87m4iI9O3dd9/FSy+9BACIjY3F+vXr6y0TGBiIP/7xj06OjIiImuLUIuGhhx7CN998g0OHDmH79u0oLS2Fj48PQkND8dJLL2HWrFno3r27M0MiIiIVFRYW2v+2PRehrp/97GcsEoiIXIxTi4Tw8HCkpKQ48yOJiEhDSUlJSEpK0joMIiJqIZe6cZmIiIiIiLTHIoGIiIiIiGRYJBARERERkQyLBCIiIiIiknHqjcuu5saNG1qHoDrHNhq9vUZvX1OsVqvWIahK7fYZff0BYrTxdtzd3bUOQXWObbx165aGkajPsX3ctsaidvsqKipUfX9XoEQbTZIkSQrEoismk0nrEIiolcrKymA2m9v8PlarFX5+fgpEpD+ipf24uDitQyCiVtq6dSu8vb3b/D4VFRUYN26cAhHpz44dO1r1OiEvN7JYLFqHQEStYLFY4Ovrq8h7+fr6CpkLRGxzWFiY1iEQUSuEhYXBy8tLkffy8vISMhe0pc1CnkmQJAnl5eVah+E0tk0swhkUkdoKiNdeX19fRdsqWi4AlF+HeiBJEm7evKl1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yclBVFQUgoKCMGXKFNy4cUPrkADoZ/01xUOtN66srMTEiRNhtVrh7++PpKQk3HfffQgICAAAdOrUSa2PdjknT55ERUUFAGDQoEGyebakUjfZ6JUobS0vL0dcXBxyc3MRERGBjIwMdOjQAQCQlJSE5ORkzJ8/HwkJCejYsSNGjBihccRtExUVhfXr1yMiIgJHjhypt22paUZffy3J96+99ppWYapKtJwAGL9fN0SUY5xetu3169cxatQoXLhwAQCQlpYGf39/LFu2TNO49LL+bke1MwkfffQRzp49CwBYvHgxXnjhBVgsFoSHhyM8PBwhISFqfbTLycnJAQD4+fmhT58+9unl5eUoKCgAYIykAojT1kWLFiE3NxcmkwkbNmywfxmwmTdvHiwWC2pqajB16lSX+WWjNeLj4/H555+jR48emDZtGh577DGtQ9IVEdYf871YOQEQo183RIRjnJ62bVZWlr1AsNm8ebNG0dTS0/q7HdWKhD179gAAPDw8hL9BLTc3FwAwcOBAuLn9tMqPHTuG6upqALVVpxGI0NarV69i6dKlAACLxdLoAWHGjBkAai9BWLVqldPiU1rPnj2xd+9ehIeHY+3atfZLSKh5RFh/oud70XICIEa/bogIxzg9bduamppmTXMmPa2/21GtSPjss88A1O5ItlPOInK8frHu6SZbsgkJCUG3bt2cHpvSRGnrjh07UFZWBgAYNWpUo8uNHDnSfhDR+peNtti0aRNGjhyJ8+fPax2KLomw/kTP96LlBECMfl2XKMc4PW3bmJiYepevjx07VqNoaulp/d2OovckzJ8/H8nJybJpOTk5MJlM9v8HBwejuLhYyY91GUVFRRg9enSj81NTU5GamlpvenFxcb2bWtLT0136xieR2lrX7t277X839YuRv78/+vbti1OnTiE7OxslJSUIDg52RoiKunTpktYh6JpR15/o+d6RaDkBMG6/thH5GKenbRsQEID09HQkJibi22+/RXx8PP7yl79oGpOe1t/tKFokHD9+/LbLOOsJm/3793fK55B4bL8kAUBoaGiTy4aGhuLUqVMAaveP2NhYVWOj2i+qzzzzDAoLCzF27FikpKTAx8dH67AMx5XyPdB0zu/Vq5eqn82cQKSdoUOH4ujRo1qHYUiKFgnLly9HcnIytm3bhqSkJADAxo0bERkZaV8mMDBQyY90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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" } ], "source": [ "partial_luts = [\n", - " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", - " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")], \n", + " # [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " # [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " # [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", + " # [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " # [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " # [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"-1--\", \"0\")],\n", + " # [(\"-1--\", \"1\")],\n", + " # [(\"-1--\",\"?\")]\n", "]\n", - "partial_lut = partial_luts[3]\n", - "\n", + "# partial_lut = partial_luts[4]\n", "\n", "# generating a node with a required bias\n", "\n", + "# generated_nodes = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.5)\n", "\n", - "\"\"\"\n", - "# Fill missing output values with the specified bias or with specified effective connectivity or randomly\n", - "generated_node = BooleanNode.from_output_list(partial_lut)\n", - "required_node_bias = 0.5 # Required bias of the node\n", - "verbose = True # Set to True to display the steps of the function\n", - "\n", - "if required_node_bias is not None: # If required node bias is specified, then fill missing output values with the specified bias.\n", - "\n", - " # Checking if required node bias is within the achievable bias range of the node.\n", - "\n", - " # Calculating max achievable bias\n", - " max_achievable_output = ['1' if output == '?' else output for output in generated_node.outputs]\n", - " max_achievable_bias = sum(map(int, max_achievable_output))/2**generated_node.k\n", - " min_achievable_bias = generated_node.bias(verbose=False)\n", - "\n", - " # Calculating the number of '1' required to achieve the required bias.\n", - " required_ones = int(required_node_bias * 2**generated_node.k)\n", - " current_ones = generated_node.outputs.count('1')\n", - "\n", - " # Checking if the required bias is achievable.\n", - " if required_node_bias > max_achievable_bias:\n", - " if verbose:\n", - " print(f\"Required Node Bias is greater than the maximum achievable bias ({max_achievable_bias}) of the node. Generating with the maximum achievable bias.\")\n", - " required_node_bias = max_achievable_bias\n", - " \n", - " elif required_node_bias < min_achievable_bias:\n", - " min_achievable_bias = generated_node.bias(verbose=False)\n", - " if verbose:\n", - " print(f\"Required Node Bias is lower than the minimum achievable bias (bias = {min_achievable_bias}) of the node. Generating with the minimum achievable bias.\")\n", - " required_node_bias = min_achievable_bias\n", - " \n", - " # Fill the missing output values to achieve the required bias as closely as possible.\n", - " required_ones = int(required_node_bias * 2**generated_node.k) # recalculating in case the required bias was adjusted in the above steps.\n", - " ones_to_be_generated = required_ones - current_ones\n", - " number_of_missing_values = generated_node.outputs.count('?') \n", - "\n", - " missing_output_values = ['1'] * ones_to_be_generated + ['0'] * (number_of_missing_values - ones_to_be_generated) # creating a shuffled list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias.\n", - " random.shuffle(missing_output_values)\n", - " generated_node.outputs = [missing_output_values.pop() if output== '?' else output for output in generated_node.outputs]\n", - "\n", - " if verbose:\n", - " print(f\"Generated the node with a bias of {generated_node.bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {required_node_bias}.\")\n", - "\"\"\"\n", + "# len(generated_nodes)\n", + "# generated_nodes[0].look_up_table()\n", "\n", - "generated_node = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.5) \n", - "print(generated_node)\n", - "# plot_look_up_table(generated_node)\n", - "plot_schemata(generated_node)" + "\n", + "for lut in partial_luts:\n", + " node = BooleanNode.from_partial_lut(lut, verbose=True)\n", + " print(node.outputs)\n", + "\n", + " generated_node_permuations = node.generate_with_required_bias(\n", + " required_node_bias=0.49, limit=1000, verbose=True\n", + " )\n", + " # print(generated_node_permuations[0].outputs, \"\\n\")\n", + "for node in generated_node_permuations:\n", + " print(node.outputs)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -381,74 +444,76 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Generated the node with the closest possible effective connectivity of 0.42447916666666674.\n" + "['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1'] \n", + "\n", + "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '0', '1'] \n", + "\n", + "['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '1', '0'] \n", + "\n", + "['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '0', '1', '1', '0', '0'] \n", + "\n", + "['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0'] \n", + "\n", + "['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '1', '0', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', '0'] \n", + "\n", + "['?', '?', '?', '?', '1', '1', '1', '1', '?', '?', '?', '?', '1', '1', '1', '1']\n", + "Generated the node with the closest possible effective connectivity of 0.484375.\n", + "['0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '1'] \n", + "\n" ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" } ], "source": [ "partial_luts = [\n", - " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", + " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " # [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"1\"), (\"01-1\", \"1\")],\n", - " \n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"-1--\", \"0\")],\n", + " [(\"-1--\", \"1\")],\n", + " # [(\"-1--\",\"?\")]\n", "]\n", "partial_lut = partial_luts[0]\n", "\n", - "\"\"\"\n", - "# Inner workings of the from_partial_lut() function under BooleanNode class\n", - "\n", - "required_effective_connectivity = .7\n", - "\n", - "generated_outputs = generated_node.outputs.copy()\n", - "missing_output_indices = [i for i, x in enumerate(generated_outputs) if x == '?']\n", - "print(f\"Missing output indices = {missing_output_indices}.\")\n", - "\n", - "missing_output_count = generated_outputs.count('?')\n", - "print(f\"No. of '?' in output = {missing_output_count}.\")\n", - "permutations = list(product(*[('0', '1')] * (missing_output_count)))\n", - "print(permutations) \n", - "generated_node_permutations = [None] * len(permutations)\n", + "for partial_lut in partial_luts:\n", + " generated_nodes = BooleanNode.from_partial_lut(partial_lut)\n", + " print(generated_nodes.outputs)\n", + " generated_node_permuations = (\n", + " generated_nodes.generate_with_required_effective_connectivity(\n", + " required_effective_connectivity=0.49, verbose=True\n", + " )\n", + " )\n", + " print(generated_node_permuations.outputs, \"\\n\")\n", "\n", - "for count, permutation in enumerate(permutations):\n", - " for i, index in enumerate(missing_output_indices):\n", - " generated_outputs[index] = permutation[i]\n", - " generated_node_permutations[count] = BooleanNode.from_output_list(generated_outputs)\n", "\n", - "print(f\"Total output permutations generated = {len(generated_node_permutations)}.\")\n", - "\n", - "permutation_effective_connectivity = [x.effective_connectivity() for x in generated_node_permutations]\n", - "print(permutation_effective_connectivity)\n", - "closest_value = min(permutation_effective_connectivity, key=lambda x: abs(x - required_effective_connectivity))\n", - "print(f\"Closest value to required effective connectivity: {closest_value}\")\n", - "\n", - "closest_index = permutation_effective_connectivity.index(closest_value)\n", - "generated_node_permutations[closest_index].look_up_table()\n", - "\n", - "\"\"\"\n", - "\n", - "# Incorporating the above functions into the from_partial_lut() under BooleanNode class\n", - "generated_node = BooleanNode.from_partial_lut(partial_lut, required_effective_connectivity=0.45)\n", + "# # Incorporating the above functions into the from_partial_lut() under BooleanNode class\n", + "# generated_node = BooleanNode.from_partial_lut(\n", + "# partial_lut, required_effective_connectivity=0.45\n", + "# )\n", "\n", "# plot_look_up_table(generated_node)\n", - "plot_schemata(generated_node)" + "# plot_schemata(generated_node)" ] }, { @@ -470,6 +535,283 @@ "ValueError: Only one of required_effective_connectvity, required_node_bias and fill_missing_output_randomly can be True. Please set the rest to False.\n", "```" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## automata rules samples" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
InputOutput
0##00###0
1##0#0#00
2###10#00
30##0###0
40###0#00
5###11##1
61#10###1
7###1##11
81#1#1##1
91#1###11
\n", + "
" + ], + "text/plain": [ + " Input Output\n", + "0 ##00### 0\n", + "1 ##0#0#0 0\n", + "2 ###10#0 0\n", + "3 0##0### 0\n", + "4 0###0#0 0\n", + "5 ###11## 1\n", + "6 1#10### 1\n", + "7 ###1##1 1\n", + "8 1#1#1## 1\n", + "9 1#1###1 1" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "GKL_BIN = \"00000000_01011111_00000000_01011111_00000000_01011111_00000000_01011111_00000000_01011111_11111111_01011111_00000000_01011111_11111111_01011111\"\n", + "GP_BIN = \"00000101_00000000_01010101_00000101_00000101_00000000_01010101_00000101_01010101_11111111_01010101_11111111_01010101_11111111_01010101_11111111\"\n", + "GEP_1_BIN = \"00010001_00000000_01010101_00000000_00010001_00001111_01010101_00001111_00010001_11111111_01010101_11111111_00010001_11111111_01010101_11111111\"\n", + "GEP_2_BIN = \"00000000_01010101_00000000_01110111_00000000_01010101_00000000_01110111_00001111_01010101_00001111_01110111_11111111_01010101_11111111_01110111\"\n", + "Davis_BIN = \"00000000_00101111_00000011_01011111_00000000_00011111_11001111_00011111_00000000_00101111_11111100_01011111_00000000_00011111_11111111_00011111\"\n", + "Das_BIN = \"00000111_00000000_00000111_11111111_00001111_00000000_00001111_11111111_00001111_00000000_00000111_11111111_00001111_00110001_00001111_11111111\"\n", + "ABK_BIN = \"00000101_00000000_01010101_00000101_00000101_00000000_01010101_00000101_01010101_11111111_01010101_11111111_01010101_11111111_01010101_11111111\"\n", + "DMC_BIN = \"00000101_00000100_00000101_10000111_00000101_00000000_00001111_01110111_00000011_01110111_01010101_10000011_01111011_11111111_10110111_01111111\"\n", + "COE_1_BIN = \"00000001_00010100_00110000_11010111_00010001_00001111_00111001_01010111_00000101_10110100_11111111_00010111_11110001_01111101_11111001_01010111\"\n", + "COE_2_BIN = \"00010100_01010001_00110000_01011100_00000000_01010000_11001110_01011111_00010111_00010001_11111111_01011111_00001111_01010011_11001111_01011111\"\n", + "MM401_BIN = \"11111111_10101010_11111111_10101000_11111111_10101010_11111111_10101000_11110000_10101010_00000000_10101000_00000000_10101010_00000000_10101000\"\n", + "\n", + "\n", + "GKL_LUT = [int(x) for x in GKL_BIN if x != \"_\"]\n", + "GP_LUT = [int(x) for x in GP_BIN if x != \"_\"]\n", + "GEP_1_LUT = [int(x) for x in GEP_1_BIN if x != \"_\"]\n", + "GEP_2_LUT = [int(x) for x in GEP_2_BIN if x != \"_\"]\n", + "Das_LUT = [int(x) for x in Das_BIN if x != \"_\"]\n", + "Davis_LUT = [int(x) for x in Davis_BIN if x != \"_\"]\n", + "ABK_LUT = [int(x) for x in ABK_BIN if x != \"_\"]\n", + "DMC_LUT = [int(x) for x in DMC_BIN if x != \"_\"]\n", + "COE_1_LUT = [int(x) for x in COE_1_BIN if x != \"_\"]\n", + "COE_2_LUT = [int(x) for x in COE_2_BIN if x != \"_\"]\n", + "MM401_LUT = [int(x) for x in MM401_BIN if x != \"_\"]\n", + "\n", + "\n", + "GKL_NODE = BooleanNode.from_output_list(outputs = GKL_LUT)\n", + "GP_NODE = BooleanNode.from_output_list(outputs = GP_LUT)\n", + "GEP_1_NODE = BooleanNode.from_output_list(outputs = GEP_1_LUT)\n", + "GEP_2_NODE = BooleanNode.from_output_list(outputs = GEP_2_LUT)\n", + "Das_NODE = BooleanNode.from_output_list(outputs = Das_LUT)\n", + "Davis_NODE = BooleanNode.from_output_list(outputs = Davis_LUT)\n", + "ABK_NODE = BooleanNode.from_output_list(outputs = ABK_LUT)\n", + "DMC_NODE = BooleanNode.from_output_list(outputs = DMC_LUT)\n", + "COE_1_NODE = BooleanNode.from_output_list(outputs = COE_1_LUT)\n", + "COE_2_NODE = BooleanNode.from_output_list(outputs = COE_2_LUT)\n", + "MM401_NODE = BooleanNode.from_output_list(outputs = MM401_LUT)\n", + "\n", + "GKL_NODE.schemata_look_up_table()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1']\n", + "0.5\n" + ] + } + ], + "source": [ + "automata = {\n", + "'GKL' : [['0###0#0', 0], ['##0#0#0', 0], ['###10#0', 0], ['##00###', 0], ['0##0###', 0], ['1#1###1', 1], ['###1##1', 1], ['###11##', 1], ['1#10###', 1], ['1#1#1##', 1]],\n", + "'GP' : [['0#01###', 0], ['0##10##', 0], ['0#####0', 0], ['###0##0', 0], ['0#0#0##', 0], ['##1#1#1', 1], ['1#####1', 1], ['1##1###', 1], ['##10##1', 1], ['###01#1', 1]],\n", + "'GEP_1' : [['000##0#', 0], ['0###0#0', 0], ['0##10##', 0], ['0#0#00#', 0], ['###0##0', 0], ['00####0', 0], ['##00#0#', 0], ['00#1###', 0], ['1#1###1', 1], ['#11#1#1', 1], ['#1#11##', 1], ['1####11', 1], ['#1##111', 1], ['1##1###', 1], ['##10##1', 1], ['###0#11', 1]],\n", + "'GEP_2':[['0#0###0', 0], ['0####00', 0], ['#0##000', 0], ['###1#00', 0], ['#00#0#0', 0], ['##01##0', 0], ['0##0###', 0], ['#0#00##', 0], ['11####1', 1], ['111##1#', 1], ['###1##1', 1], ['11#0###', 1], ['1##01##', 1], ['1#1#11#', 1], ['1###1#1', 1], ['##11#1#', 1]],\n", + "'Das': [['000##00', 0], ['#010#00', 0], ['0#01###', 0], ['###00##', 0], ['#001###', 0], ['0#0#0##', 0], ['##0#00#', 0], ['##01#0#', 0], ['00#0#00', 0], ['#00#0##', 0], ['##011#0', 0], ['##1#11#', 1], ['11#101#', 1], ['###01#1', 1], ['#1#01##', 1], ['###011#', 1], ['#11#1##', 1], ['##1#1#1', 1], ['11#1#11', 1], ['1#001##', 1], ['11##111', 1], ['##11###', 1]],\n", + "'Davis':[['#10#0#0', 0], ['00#00##', 0], ['##110#0', 0], ['#00#0#1', 0], ['10#011#', 0], ['01##010', 0], ['###1000', 0], ['00#0#0#', 0], ['00##000', 0], ['#1#100#', 0], ['001#0#0', 0], ['0#1#010', 0], ['##0#00#', 0], ['#1#10#0', 0], ['##00###', 0], ['0##001#', 0], ['#1#1#11', 1], ['#011##1', 1], ['0#1#11#', 1], ['#110#0#', 1], ['101#0#1', 1], ['111##11', 1], ['#001#10', 1], ['101##01', 1], ['1#1#10#', 1], ['1110###', 1], ['##11#11', 1], ['#11#1##', 1], ['1#100##', 1], ['1#1#011', 1], ['###11##', 1], ['1#10#0#', 1]],\n", + "'ABK':[['0#01###', 0], ['0##10##', 0], ['0#####0', 0], ['###0##0', 0], ['0#0#0##', 0], ['##1#1#1', 1], ['1#####1', 1], ['1##1###', 1], ['##10##1', 1], ['###01#1', 1]],\n", + "'DMC': [['00##01#', 0], ['0#0###0', 0], ['1011#01', 0], ['01##000', 0], ['#110001', 0], ['1#00101', 0], ['#01#010', 0], ['#0#00#0', 0], ['#111000', 0], ['0#01#1#', 0], ['1#10100', 0], ['101110#', 0], ['#0110#1', 0], ['00##0#1', 0], ['0##00##', 0], ['##00000', 0], ['#0##100', 0], ['#010##0', 0], ['00#0##0', 0], ['#0000##', 0], ['0#0#0##', 0], ['0101###', 0], ['#01101#', 0], ['0##1100', 0], ['#0#0#00', 0], ['1000#0#', 0], ['#00##00', 0], ['01#1#00', 0], ['###0111', 1], ['1#0#11#', 1], ['01101##', 1], ['11###1#', 1], ['110#0#1', 1], ['#11#11#', 1], ['#111#1#', 1], ['0#1#1#1', 1], ['1101###', 1], ['1#01#1#', 1], ['1##111#', 1], ['##1#111', 1], ['1#01##1', 1], ['00##101', 1], ['110#1#0', 1], ['##101#1', 1], ['1#10#11', 1], ['#11#1#1', 1], ['1###111', 1], ['11#11##', 1], ['1010##1', 1], ['##1111#', 1], ['0##01#1', 1], ['#111##1', 1], ['#001101', 1], ['11100#0', 1], ['11#1##1', 1], ['#011000', 1]],\n", + "'COE_1': [['01010##', 0], ['00#01#0', 0], ['#00#001', 0], ['00#0#0#', 0], ['#1#0110', 0], ['01##000', 0], ['#000##0', 0], ['0#0#0#0', 0], ['#00#1#0', 0], ['0#00#0#', 0], ['1#11#00', 0], ['00101##', 0], ['000###0', 0], ['#0000##', 0], ['##11010', 0], ['0#00##0', 0], ['#0#1100', 0], ['#1#1000', 0], ['0##0110', 0], ['#00111#', 0], ['00##100', 0], ['##11100', 0], ['1#0#110', 0], ['#10010#', 0], ['#1#0101', 0], ['0##000#', 0], ['1#110#0', 0], ['101100#', 0], ['0#0#00#', 0], ['##001#0', 0], ['0##1010', 0], ['01#10#0', 0], ['10#1001', 0], ['#111#00', 0], ['#1110#0', 0], ['0##0#01', 0], ['11###11', 1], ['001100#', 1], ['101#11#', 1], ['110#01#', 1], ['1##1011', 1], ['01011##', 1], ['10##101', 1], ['##1#011', 1], ['###1101', 1], ['11##0#1', 1], ['#1#0#11', 1], ['#1#11#1', 1], ['10#01#1', 1], ['#11##11', 1], ['##1111#', 1], ['#111##1', 1], ['101#1#1', 1], ['01#111#', 1], ['1#0101#', 1], ['#1##111', 1], ['1#100##', 1], ['1#10#00', 1], ['##111#1', 1], ['10010#0', 1], ['#0#1011', 1], ['#110100', 1], ['1010###', 1], ['11#00##', 1], ['##11#11', 1], ['#10110#', 1], ['11#1##1', 1], ['1#1##11', 1], ['##00111', 1], ['1##0111', 1], ['0#11##1', 1], ['##1001#', 1]],\n", + "'COE_2':[['00#011#', 0], ['00#01#0', 0], ['0#0###0', 0], ['0##0111', 0], ['001#11#', 0], ['100#00#', 0], ['##0110#', 0], ['00#0#00', 0], ['00101##', 0], ['#1#001#', 0], ['##01#00', 0], ['00##110', 0], ['01#0#11', 0], ['1001#0#', 0], ['#001##0', 0], ['0100###', 0], ['#1##010', 0], ['##0#0#0', 0], ['###10#0', 0], ['00##000', 0], ['00#000#', 0], ['#1000##', 0], ['0010#0#', 0], ['0#0011#', 0], ['##0000#', 0], ['010#1##', 0], ['00#1#10', 0], ['#00##00', 0], ['#11##01', 1], ['1##1#11', 1], ['##110#1', 1], ['0##10#1', 1], ['11#01##', 1], ['1#10#0#', 1], ['1#1#1##', 1], ['#1#10#1', 1], ['#1111##', 1], ['#001#11', 1], ['101###1', 1], ['#11#10#', 1], ['#11#1#0', 1], ['#110#0#', 1], ['10###11', 1], ['11##11#', 1], ['1010###', 1], ['##1110#', 1], ['1###111', 1], ['#01001#', 1], ['#0##011', 1], ['#000101', 1], ['##11#01', 1], ['#111##1', 1], ['###1011', 1], ['1##01#1', 1], ['1#11##1', 1], ['1##011#', 1], ['1#1##01', 1]],\n", + "'MM401':[['11####1', 0], ['1#1###1', 0], ['###1##1', 0], ['1#10###', 0], ['##1111#', 0], ['11#0###', 0], ['1##01##', 0], ['1#1#11#', 0], ['1###1#1', 0], ['0###0#0', 1], ['0#0###0', 1], ['#0000##', 1], ['0####00', 1], ['###10#0', 1], ['###1#00', 1], ['#00#0#0', 1], ['##01##0', 1], ['0##0###', 1]],\n", + "}\n", + "\n", + "gkl_node = BooleanNode.from_partial_lut(automata['GKL'])\n", + "print(gkl_node.outputs)\n", + "print(gkl_node.bias())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "GKL_INCOMPLETE = [['0###0#0', 0], ['##0#0#0', 0], ['###10#0', 0], ['##00###', 0], ['1#1###1', 1], ['###1##1', 1], ['###11##', 1],['1#1#1##', 1],] #,['1#10###', 1] ['0##0###', 0]\n", + "\n", + "node = BooleanNode.from_partial_lut(GKL_INCOMPLETE, verbose=True)\n", + "print(node.outputs)\n", + "\n", + "# node = node.BooleanNode.from_partial_lut(GKL_INCOMPLETE, fill_missing_output_randomly=True)\n", + "node = node.generate_with_required_bias(required_node_bias=0.5, limit=100, verbose=True)\n", + "print(node[0].outputs)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# # plot_schemata(GKL_NODE)\n", + "# gkl_lut= MM401_NODE.schemata_look_up_table()\n", + "# gkl = [list(item) for item in zip(gkl_lut['Input'].tolist(), gkl_lut['Output'].tolist())]\n", + "# print(gkl)\n", + "# # gkl_lut" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "128" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "partial_lut= GKL.copy()\n", + "all_states = dict(partial_lut)\n", + "for entry in partial_lut:\n", + " # print(entry[0])\n", + " if not all([x in [\"0\", \"1\", \"-\", \"#\", \"2\", \"x\"] for x in entry[0]]):\n", + " raise ValueError(\n", + " \"All the input entries of the partial LUT must be valid binary strings.\"\n", + " )\n", + "\n", + " elif any([x in [\"-\", \"#\", \"2\", \"x\"] for x in entry[0]]):\n", + " missing_data_indices = [i for i, x in enumerate(entry[0]) if x in [\"-\", \"#\", \"2\", \"x\"]]\n", + " table = []\n", + " output_list_permutations = []\n", + "\n", + " for i in range(2 ** len(missing_data_indices)):\n", + " row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))]\n", + " table.append(row)\n", + " output_list_permutations.append(entry[0])\n", + " for j in range(len(missing_data_indices)):\n", + " output_list_permutations[i] = (\n", + " output_list_permutations[i][: missing_data_indices[j]]\n", + " + str(table[i][j])\n", + " + output_list_permutations[i][missing_data_indices[j] + 1 :]\n", + " )\n", + "\n", + " \n", + " del all_states[entry[0]]\n", + "\n", + " for perm in output_list_permutations:\n", + " if perm in all_states and all_states[perm] != entry[1]:\n", + " print(\"Clashing output values for entry:\", perm)\n", + " all_states[perm] = \"!\"\n", + " else:\n", + " all_states[perm] = entry[1]\n", + "k = len(partial_lut[0][0])\n", + "for i in range(2**k):\n", + " state = bin(i)[2:].zfill(k)\n", + " if state not in all_states:\n", + " all_states[state] = \"?\"\n", + "\n", + "all_states = sorted(all_states.items(), key=lambda x: x[0])\n", + "len(all_states)" + ] } ], "metadata": { diff --git a/tutorials/partial_LUT_demo_nodes.txt b/tutorials/partial_LUT_demo_nodes.txt new file mode 100644 index 0000000..e2c1875 --- /dev/null +++ b/tutorials/partial_LUT_demo_nodes.txt @@ -0,0 +1,127 @@ +# A sample network with partial input data for nodes. Modified form Thaliana. + +#total number of nodes +.v 15 + +# labels of nodes and name of corresponding genes +# 1 = AP3 +# 2 = UFO +# 3 = FUL +# 4 = FT +# 5 = AP1 +# 6 = EMF1 +# 7 = LFY +# 8 = AP2 +# 9 = WUS +# 10 = AG +# 11 = LUG +# 12 = CLF +# 13 = TFL1 +# 14 = PI +# 15 = SEP + +.l 1 AP3 +.l 2 UFO +.l 3 FUL +.l 4 FT +.l 5 AP1 +.l 6 EMF1 +.l 7 LFY +.l 8 AP2 +.l 9 WUS +.l 10 AG +.l 11 LUG +.l 12 CLF +.l 13 TFL1 +.l 14 PI +.l 15 SEP + + +# As a result of simulation, we get the following 10 single-point attractors: +# 101100110111011 +# 110110110011011 +# 100110110011011 +# 111100110111011 +# 010001000011100 +# 010001001011100 +# 001100110111011 +# 000110110011001 +# 000001000011100 +# 000001001011100 + +# 1 = AP3 +.n 1 7 1 2 5 7 10 14 15 +1-1--11 1 +-1-1--- 1 + +# 2 = UFO +.n 2 1 2 +1 1 + +# 3 = FUL +.n 3 2 5 13 +00 1 + +# 4 = FT +.n 4 1 6 +0 1 + +# 5 = AP1 +.n 5 4 4 7 10 13 +--00 1 +1-0- 1 +-10- 1 + +# 6 = EMF1 +.n 6 1 7 +0 1 + +# 7 = LFY +.n 7 4 3 5 6 13 +---0 1 +--0- 1 + +# 8 = AP2 +.n 8 1 13 +0 1 + +# 9 = WUS +.n 9 3 9 10 15 +1-0 1 +10- 1 + +# 10 = AG +.n 10 9 5 7 8 9 10 11 12 13 15 +--0----0- 1 +-1--1---1 1 +-1----0-- 1 +-1---0--- 1 +01------- 1 +-1-1----- 1 +-10------ 1 + +# 11 = LUG +.n 11 0 +1 + +# 12 = CLF +.n 12 0 +1 + +# 13 = TFL1 +.n 13 4 5 6 7 8 +010- 1 + +# 14 = PI +.n 14 6 1 5 7 10 14 15 +11--11 1 +1--111 1 +--11-- 1 +1-1--- 1 + +# 15 = SEP +.n 15 1 7 +1 1 + +.e end of file + From bd7e8dd02f33f35a5b637c5d92937cbd459918c8 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Sun, 23 Jun 2024 18:20:53 -0400 Subject: [PATCH 10/14] added warnings, errors Refactor BooleanNode.generate_with_required_bias and effective connectiity for improved readability and performance reorganized partial_lut demo file --- cana/boolean_node.py | 10 +- tests/test_boolean_node.py | 40 +- tutorials/Generating from Partial LUTs.ipynb | 504 ++++++++----------- 3 files changed, 240 insertions(+), 314 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index 1b92861..5172fd1 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -1017,7 +1017,7 @@ def generate_with_required_bias( verbose (bool) : If True, print additional information. Returns: - (BooleanNode) : the instantiated object. + List of BooleanNode objects with the required bias. Example: >>> BooleanNode.generate_with_required_bias(required_node_bias=0.5, verbose=True, name="EG") @@ -1089,12 +1089,12 @@ def generate_with_required_bias( ) # create a list of all possible unique arrangements of the missing output values combinations = list(islice(set(permutations(missing_output_values)), limit)) - + generated_node_permutations = [None] * len(combinations) for count, combination in enumerate(combinations): combination = list(combination) - random.shuffle(combination) + # random.shuffle(combination) # shuffling the combination creates duplicates and misses some combinations. generated_outputs = generated_node.outputs.copy() for i, output in enumerate(generated_node.outputs): if output == "?": @@ -1112,12 +1112,12 @@ def generate_with_required_bias( print( f"Generated {len(generated_node_permutations)} node(s) with a bias of {generated_node_permutations[0].bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {bias}." ) - return generated_node_permutations + return generated_node_permutations # returning a list of BooleanNode objects with the required bias. def generate_with_required_effective_connectivity( self, required_effective_connectivity=None, - limit=50, + # limit=50, verbose=False, *args, **kwargs, diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index 4815842..94ba86a 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -817,6 +817,8 @@ def test_fill_out_lut(): def test_from_partial_lut(): + + # Test cases for BooleanNode.from_partial_lut() partial_luts = [ [("001-", "0"), ("1--1", "1"), ("11--", "1")], [("00--", "0"), ("1--1", "1"), ("110-", "1")], @@ -824,15 +826,19 @@ def test_from_partial_lut(): [("0--0", "0"), ("1--1", "0"), ("0111", "1"), ("0011", "1")], [("1-01", "1"), ("1-1-", "0"), ("0110", "0"), ("01-1", "1")], [("1-01", "1"), ("1-1-", "0"), ("0110", "0"), ("01-1", "?")], + [("-1--", "0")], + [("-1--", "1")], [("-1--", "?")], ] expected_output_lists = [ ['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1'], ['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1'], - ['?', '?', '1', '!', '1', '!', '1', '1'], + ['?', '?', '1', '!', '1', '!', '1', '1'], # with clashes ['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0'], ['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0'], ['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0'], + ['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0'], + ['?', '?', '?', '?', '1', '1', '1', '1', '?', '?', '?', '?', '1', '1', '1', '1'], ['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?'], ] @@ -843,5 +849,37 @@ def test_from_partial_lut(): assert ( generated_node.outputs == expected_output_list ), f"from_partial_lut failed: {generated_node.outputs} != {expected_output_list}" + + +def test_generate_with_required_node_bias(): + # removing some effective graph inputs to make them incomplete + incomplete_automata = { + "GKL": [["##0#0#0", 0],["###10#0", 0],["##00###", 0],["0##0###", 0],["###1##1", 1],["1#10###", 1],["1#1#1##", 1], ["1#1###1", 1],], # ["0###0#0", 0], ["###11##", 1], is missing + "GP": [["0#01###", 0],["0##10##", 0],["0#####0", 0],["###0##0", 0],["1#####1", 1],["1##1###", 1],["##10##1", 1],["###01#1", 1],], # ["0#0#00#", 0], is missing + "ABK": [["0#01###", 0],["0##10##", 0],["0#####0", 0],["###0##0", 0],["##1#1#1", 1],["1#####1", 1],["1##1###", 1],["##10##1", 1],], # ["0#0#0##", 0],["###01#1", 1], is missing + } + + automata_output_list = { + 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'], + 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'], + + 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'], + } + + for automata in incomplete_automata: + node = None + generated_node_permuations = None + node = BooleanNode.from_partial_lut(incomplete_automata[automata]) + + generated_node_permuations = BooleanNode.generate_with_required_bias( node, required_node_bias=0.5, verbose=True) + list_of_output_lists = [node.outputs for node in generated_node_permuations] + + # print(automata) + # if automata_output_list[automata] in list_of_output_lists: + # print("Found a match") + # else: + # print("No match found") + + assert automata_output_list[automata] in list_of_output_lists, "No match found" diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index 340fcf9..f209ec6 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -24,7 +24,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -130,7 +130,7 @@ "[128 rows x 2 columns]" ] }, - "execution_count": 8, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -158,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -182,7 +182,7 @@ " ('1111', '0')]" ] }, - "execution_count": 9, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -190,6 +190,7 @@ "source": [ "# Using the fill_out_lut function found in utils.py\n", "\n", + "# example look up tables\n", "partial_luts = [\n", " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")],\n", @@ -215,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -243,10 +244,10 @@ ], "source": [ "partial_luts_network = BooleanNetwork.from_file(\n", - " \"partial_LUT_demo_nodes.txt\",\n", + " \"partial_LUT_demo_nodes.txt\", # loading example network with partial LUTs in the nodes\n", " name=\"Partial LUTs Demo\",\n", " keep_constants=True,\n", - " partial_lut=True,\n", + " partial_lut=True, # specifying that the LUTs are partial, because the default assumes that all LUTs are complete\n", ")\n", "\n", "\n", @@ -271,7 +272,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -286,31 +287,28 @@ "['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0']\n", "['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0']\n", "['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", + "['?', '?', '?', '?', '1', '1', '1', '1', '?', '?', '?', '?', '1', '1', '1', '1']\n", "['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?']\n" ] } ], "source": [ + "# example partial look up tables\n", "partial_luts = [\n", - " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", - " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", - " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", - " [(\"-1--\", \"?\")],\n", + " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"-1--\", \"0\")],\n", + " [(\"-1--\", \"1\")],\n", + " [(\"-1--\", \"?\")],\n", "]\n", - "partial_lut = partial_luts[6]\n", - "\n", - "\"\"\"\n", - "generated_lut = fill_out_lut(partial_lut) # Using the fill_out_lut function found in utils.py\n", - "output_list = [x[1] for x in generated_lut] # Extracting the output values from the generated_lut\n", - "print(output_list)\n", - "generated_node = BooleanNode.from_output_list(output_list) # Instantiating a BooleanNode object from the output_list\n", - "generated_node.look_up_table() # Displaying the look-up table of the generated_node\n", - "\"\"\"\n", + "\n", + "# using the from_partial_lut function found in BooleanNode class\n", "for partial_lut in partial_luts:\n", - " # Combining the above functions into a single function under BooleanNode class\n", " generated_node = BooleanNode.from_partial_lut(partial_lut)\n", " # print(generated_node)\n", " print(generated_node.outputs)\n", @@ -318,23 +316,30 @@ " # plot_schemata(generated_node) # This will throw an error as the presence of '?' makes it impossible to generate a schemata look up table." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating missing output values randomly" + ] + }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - "['1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0']\n" + "\n", + "['0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0']\n" ] } ], "source": [ "# filling missing output values randomly with 1 or 0 instead of '?'\n", - "\n", + "partial_lut = [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"01--\", \"0\")]\n", "generated_node = BooleanNode.from_partial_lut(\n", " partial_lut, fill_missing_output_randomly=True\n", ")\n", @@ -357,68 +362,51 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The LUT is incomplete. Missing values are represented by '?'.\n", - "['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", "Generated 8 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", - "['1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0']\n", - "['0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", - "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n", - "['1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '0', '0', '0']\n", - "['1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0']\n", - "['1', '1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0']\n", - "['1', '1', '1', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0']\n" + "Generated 21 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 6 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 35 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 126 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 8 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 220 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", + "Generated 56 node(s) with a bias of 0.375. This is the closest bias less than or equal to the required bias of 0.49.\n" ] } ], "source": [ "partial_luts = [\n", - " # [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " # [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", " # [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", - " # [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", - " # [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", - " # [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", " [(\"-1--\", \"0\")],\n", - " # [(\"-1--\", \"1\")],\n", - " # [(\"-1--\",\"?\")]\n", + " [(\"-10-\", \"1\")],\n", + " [(\"11-\",\"?\")]\n", "]\n", - "# partial_lut = partial_luts[4]\n", - "\n", - "# generating a node with a required bias\n", - "\n", - "# generated_nodes = BooleanNode.from_partial_lut(partial_lut, required_node_bias=0.5)\n", - "\n", - "# len(generated_nodes)\n", - "# generated_nodes[0].look_up_table()\n", "\n", "\n", "for lut in partial_luts:\n", - " node = BooleanNode.from_partial_lut(lut, verbose=True)\n", - " print(node.outputs)\n", + " node = None\n", + " generated_node_permuations = None\n", + " node = BooleanNode.from_partial_lut(lut)\n", + " # print(node.outputs)\n", "\n", " generated_node_permuations = node.generate_with_required_bias(\n", " required_node_bias=0.49, limit=1000, verbose=True\n", " )\n", " # print(generated_node_permuations[0].outputs, \"\\n\")\n", - "for node in generated_node_permuations:\n", - " print(node.outputs)" + "\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": {}, @@ -444,38 +432,38 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", + "Partial LUT: ['?', '?', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '1', '1']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1'] \n", "\n", - "['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1']\n", + "Partial LUT: ['0', '0', '0', '0', '?', '?', '?', '?', '?', '1', '?', '1', '1', '1', '?', '1']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '0', '1'] \n", "\n", - "['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0']\n", + "Partial LUT: ['0', '?', '0', '1', '0', '?', '0', '1', '?', '0', '?', '0', '?', '0', '?', '0']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '1', '0'] \n", "\n", - "['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "Partial LUT: ['?', '?', '?', '?', '?', '1', '0', '1', '?', '1', '0', '0', '?', '1', '0', '0']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '0', '1', '1', '0', '0'] \n", "\n", - "['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0']\n", + "Partial LUT: ['?', '?', '?', '?', '?', '?', '0', '?', '?', '1', '0', '0', '?', '1', '0', '0']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0'] \n", "\n", - "['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", + "Partial LUT: ['?', '?', '?', '?', '0', '0', '0', '0', '?', '?', '?', '?', '0', '0', '0', '0']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '1', '0', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', '0'] \n", "\n", - "['?', '?', '?', '?', '1', '1', '1', '1', '?', '?', '?', '?', '1', '1', '1', '1']\n", + "Partial LUT: ['?', '?', '?', '?', '1', '1', '1', '1', '?', '?', '?', '?', '1', '1', '1', '1']\n", "Generated the node with the closest possible effective connectivity of 0.484375.\n", "['0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '1'] \n", "\n" @@ -498,7 +486,7 @@ "\n", "for partial_lut in partial_luts:\n", " generated_nodes = BooleanNode.from_partial_lut(partial_lut)\n", - " print(generated_nodes.outputs)\n", + " print(f\"Partial LUT: {generated_nodes.outputs}\")\n", " generated_node_permuations = (\n", " generated_nodes.generate_with_required_effective_connectivity(\n", " required_effective_connectivity=0.49, verbose=True\n", @@ -544,273 +532,173 @@ ] }, { - "cell_type": "code", - "execution_count": 15, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
InputOutput
0##00###0
1##0#0#00
2###10#00
30##0###0
40###0#00
5###11##1
61#10###1
7###1##11
81#1#1##1
91#1###11
\n", - "
" - ], - "text/plain": [ - " Input Output\n", - "0 ##00### 0\n", - "1 ##0#0#0 0\n", - "2 ###10#0 0\n", - "3 0##0### 0\n", - "4 0###0#0 0\n", - "5 ###11## 1\n", - "6 1#10### 1\n", - "7 ###1##1 1\n", - "8 1#1#1## 1\n", - "9 1#1###1 1" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "GKL_BIN = \"00000000_01011111_00000000_01011111_00000000_01011111_00000000_01011111_00000000_01011111_11111111_01011111_00000000_01011111_11111111_01011111\"\n", - "GP_BIN = \"00000101_00000000_01010101_00000101_00000101_00000000_01010101_00000101_01010101_11111111_01010101_11111111_01010101_11111111_01010101_11111111\"\n", - "GEP_1_BIN = \"00010001_00000000_01010101_00000000_00010001_00001111_01010101_00001111_00010001_11111111_01010101_11111111_00010001_11111111_01010101_11111111\"\n", - "GEP_2_BIN = \"00000000_01010101_00000000_01110111_00000000_01010101_00000000_01110111_00001111_01010101_00001111_01110111_11111111_01010101_11111111_01110111\"\n", - "Davis_BIN = \"00000000_00101111_00000011_01011111_00000000_00011111_11001111_00011111_00000000_00101111_11111100_01011111_00000000_00011111_11111111_00011111\"\n", - "Das_BIN = \"00000111_00000000_00000111_11111111_00001111_00000000_00001111_11111111_00001111_00000000_00000111_11111111_00001111_00110001_00001111_11111111\"\n", - "ABK_BIN = \"00000101_00000000_01010101_00000101_00000101_00000000_01010101_00000101_01010101_11111111_01010101_11111111_01010101_11111111_01010101_11111111\"\n", - "DMC_BIN = \"00000101_00000100_00000101_10000111_00000101_00000000_00001111_01110111_00000011_01110111_01010101_10000011_01111011_11111111_10110111_01111111\"\n", - "COE_1_BIN = \"00000001_00010100_00110000_11010111_00010001_00001111_00111001_01010111_00000101_10110100_11111111_00010111_11110001_01111101_11111001_01010111\"\n", - "COE_2_BIN = \"00010100_01010001_00110000_01011100_00000000_01010000_11001110_01011111_00010111_00010001_11111111_01011111_00001111_01010011_11001111_01011111\"\n", - "MM401_BIN = \"11111111_10101010_11111111_10101000_11111111_10101010_11111111_10101000_11110000_10101010_00000000_10101000_00000000_10101010_00000000_10101000\"\n", - "\n", - "\n", - "GKL_LUT = [int(x) for x in GKL_BIN if x != \"_\"]\n", - "GP_LUT = [int(x) for x in GP_BIN if x != \"_\"]\n", - "GEP_1_LUT = [int(x) for x in GEP_1_BIN if x != \"_\"]\n", - "GEP_2_LUT = [int(x) for x in GEP_2_BIN if x != \"_\"]\n", - "Das_LUT = [int(x) for x in Das_BIN if x != \"_\"]\n", - "Davis_LUT = [int(x) for x in Davis_BIN if x != \"_\"]\n", - "ABK_LUT = [int(x) for x in ABK_BIN if x != \"_\"]\n", - "DMC_LUT = [int(x) for x in DMC_BIN if x != \"_\"]\n", - "COE_1_LUT = [int(x) for x in COE_1_BIN if x != \"_\"]\n", - "COE_2_LUT = [int(x) for x in COE_2_BIN if x != \"_\"]\n", - "MM401_LUT = [int(x) for x in MM401_BIN if x != \"_\"]\n", - "\n", - "\n", - "GKL_NODE = BooleanNode.from_output_list(outputs = GKL_LUT)\n", - "GP_NODE = BooleanNode.from_output_list(outputs = GP_LUT)\n", - "GEP_1_NODE = BooleanNode.from_output_list(outputs = GEP_1_LUT)\n", - "GEP_2_NODE = BooleanNode.from_output_list(outputs = GEP_2_LUT)\n", - "Das_NODE = BooleanNode.from_output_list(outputs = Das_LUT)\n", - "Davis_NODE = BooleanNode.from_output_list(outputs = Davis_LUT)\n", - "ABK_NODE = BooleanNode.from_output_list(outputs = ABK_LUT)\n", - "DMC_NODE = BooleanNode.from_output_list(outputs = DMC_LUT)\n", - "COE_1_NODE = BooleanNode.from_output_list(outputs = COE_1_LUT)\n", - "COE_2_NODE = BooleanNode.from_output_list(outputs = COE_2_LUT)\n", - "MM401_NODE = BooleanNode.from_output_list(outputs = MM401_LUT)\n", - "\n", - "GKL_NODE.schemata_look_up_table()" + "## list of DCT automata" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1']\n", - "0.5\n" + "Bias of GKL = 0.5\n", + "Bias of GP = 0.5\n", + "Bias of GEP_1 = 0.5\n", + "Bias of GEP_2 = 0.5\n", + "Bias of Davis = 0.5\n", + "Bias of Das = 0.5\n", + "Bias of ABK = 0.5\n", + "Bias of DMC = 0.4921875\n", + "Bias of COE_1 = 0.515625\n", + "Bias of COE_2 = 0.5\n", + "Bias of MM401 = 0.5\n" ] } ], "source": [ - "automata = {\n", - "'GKL' : [['0###0#0', 0], ['##0#0#0', 0], ['###10#0', 0], ['##00###', 0], ['0##0###', 0], ['1#1###1', 1], ['###1##1', 1], ['###11##', 1], ['1#10###', 1], ['1#1#1##', 1]],\n", - "'GP' : [['0#01###', 0], ['0##10##', 0], ['0#####0', 0], ['###0##0', 0], ['0#0#0##', 0], ['##1#1#1', 1], ['1#####1', 1], ['1##1###', 1], ['##10##1', 1], ['###01#1', 1]],\n", - "'GEP_1' : [['000##0#', 0], ['0###0#0', 0], ['0##10##', 0], ['0#0#00#', 0], ['###0##0', 0], ['00####0', 0], ['##00#0#', 0], ['00#1###', 0], ['1#1###1', 1], ['#11#1#1', 1], ['#1#11##', 1], ['1####11', 1], ['#1##111', 1], ['1##1###', 1], ['##10##1', 1], ['###0#11', 1]],\n", - "'GEP_2':[['0#0###0', 0], ['0####00', 0], ['#0##000', 0], ['###1#00', 0], ['#00#0#0', 0], ['##01##0', 0], ['0##0###', 0], ['#0#00##', 0], ['11####1', 1], ['111##1#', 1], ['###1##1', 1], ['11#0###', 1], ['1##01##', 1], ['1#1#11#', 1], ['1###1#1', 1], ['##11#1#', 1]],\n", - "'Das': [['000##00', 0], ['#010#00', 0], ['0#01###', 0], ['###00##', 0], ['#001###', 0], ['0#0#0##', 0], ['##0#00#', 0], ['##01#0#', 0], ['00#0#00', 0], ['#00#0##', 0], ['##011#0', 0], ['##1#11#', 1], ['11#101#', 1], ['###01#1', 1], ['#1#01##', 1], ['###011#', 1], ['#11#1##', 1], ['##1#1#1', 1], ['11#1#11', 1], ['1#001##', 1], ['11##111', 1], ['##11###', 1]],\n", - "'Davis':[['#10#0#0', 0], ['00#00##', 0], ['##110#0', 0], ['#00#0#1', 0], ['10#011#', 0], ['01##010', 0], ['###1000', 0], ['00#0#0#', 0], ['00##000', 0], ['#1#100#', 0], ['001#0#0', 0], ['0#1#010', 0], ['##0#00#', 0], ['#1#10#0', 0], ['##00###', 0], ['0##001#', 0], ['#1#1#11', 1], ['#011##1', 1], ['0#1#11#', 1], ['#110#0#', 1], ['101#0#1', 1], ['111##11', 1], ['#001#10', 1], ['101##01', 1], ['1#1#10#', 1], ['1110###', 1], ['##11#11', 1], ['#11#1##', 1], ['1#100##', 1], ['1#1#011', 1], ['###11##', 1], ['1#10#0#', 1]],\n", - "'ABK':[['0#01###', 0], ['0##10##', 0], ['0#####0', 0], ['###0##0', 0], ['0#0#0##', 0], ['##1#1#1', 1], ['1#####1', 1], ['1##1###', 1], ['##10##1', 1], ['###01#1', 1]],\n", - "'DMC': [['00##01#', 0], ['0#0###0', 0], ['1011#01', 0], ['01##000', 0], ['#110001', 0], ['1#00101', 0], ['#01#010', 0], ['#0#00#0', 0], ['#111000', 0], ['0#01#1#', 0], ['1#10100', 0], ['101110#', 0], ['#0110#1', 0], ['00##0#1', 0], ['0##00##', 0], ['##00000', 0], ['#0##100', 0], ['#010##0', 0], ['00#0##0', 0], ['#0000##', 0], ['0#0#0##', 0], ['0101###', 0], ['#01101#', 0], ['0##1100', 0], ['#0#0#00', 0], ['1000#0#', 0], ['#00##00', 0], ['01#1#00', 0], ['###0111', 1], ['1#0#11#', 1], ['01101##', 1], ['11###1#', 1], ['110#0#1', 1], ['#11#11#', 1], ['#111#1#', 1], ['0#1#1#1', 1], ['1101###', 1], ['1#01#1#', 1], ['1##111#', 1], ['##1#111', 1], ['1#01##1', 1], ['00##101', 1], ['110#1#0', 1], ['##101#1', 1], ['1#10#11', 1], ['#11#1#1', 1], ['1###111', 1], ['11#11##', 1], ['1010##1', 1], ['##1111#', 1], ['0##01#1', 1], ['#111##1', 1], ['#001101', 1], ['11100#0', 1], ['11#1##1', 1], ['#011000', 1]],\n", - "'COE_1': [['01010##', 0], ['00#01#0', 0], ['#00#001', 0], ['00#0#0#', 0], ['#1#0110', 0], ['01##000', 0], ['#000##0', 0], ['0#0#0#0', 0], ['#00#1#0', 0], ['0#00#0#', 0], ['1#11#00', 0], ['00101##', 0], ['000###0', 0], ['#0000##', 0], ['##11010', 0], ['0#00##0', 0], ['#0#1100', 0], ['#1#1000', 0], ['0##0110', 0], ['#00111#', 0], ['00##100', 0], ['##11100', 0], ['1#0#110', 0], ['#10010#', 0], ['#1#0101', 0], ['0##000#', 0], ['1#110#0', 0], ['101100#', 0], ['0#0#00#', 0], ['##001#0', 0], ['0##1010', 0], ['01#10#0', 0], ['10#1001', 0], ['#111#00', 0], ['#1110#0', 0], ['0##0#01', 0], ['11###11', 1], ['001100#', 1], ['101#11#', 1], ['110#01#', 1], ['1##1011', 1], ['01011##', 1], ['10##101', 1], ['##1#011', 1], ['###1101', 1], ['11##0#1', 1], ['#1#0#11', 1], ['#1#11#1', 1], ['10#01#1', 1], ['#11##11', 1], ['##1111#', 1], ['#111##1', 1], ['101#1#1', 1], ['01#111#', 1], ['1#0101#', 1], ['#1##111', 1], ['1#100##', 1], ['1#10#00', 1], ['##111#1', 1], ['10010#0', 1], ['#0#1011', 1], ['#110100', 1], ['1010###', 1], ['11#00##', 1], ['##11#11', 1], ['#10110#', 1], ['11#1##1', 1], ['1#1##11', 1], ['##00111', 1], ['1##0111', 1], ['0#11##1', 1], ['##1001#', 1]],\n", - "'COE_2':[['00#011#', 0], ['00#01#0', 0], ['0#0###0', 0], ['0##0111', 0], ['001#11#', 0], ['100#00#', 0], ['##0110#', 0], ['00#0#00', 0], ['00101##', 0], ['#1#001#', 0], ['##01#00', 0], ['00##110', 0], ['01#0#11', 0], ['1001#0#', 0], ['#001##0', 0], ['0100###', 0], ['#1##010', 0], ['##0#0#0', 0], ['###10#0', 0], ['00##000', 0], ['00#000#', 0], ['#1000##', 0], ['0010#0#', 0], ['0#0011#', 0], ['##0000#', 0], ['010#1##', 0], ['00#1#10', 0], ['#00##00', 0], ['#11##01', 1], ['1##1#11', 1], ['##110#1', 1], ['0##10#1', 1], ['11#01##', 1], ['1#10#0#', 1], ['1#1#1##', 1], ['#1#10#1', 1], ['#1111##', 1], ['#001#11', 1], ['101###1', 1], ['#11#10#', 1], ['#11#1#0', 1], ['#110#0#', 1], ['10###11', 1], ['11##11#', 1], ['1010###', 1], ['##1110#', 1], ['1###111', 1], ['#01001#', 1], ['#0##011', 1], ['#000101', 1], ['##11#01', 1], ['#111##1', 1], ['###1011', 1], ['1##01#1', 1], ['1#11##1', 1], ['1##011#', 1], ['1#1##01', 1]],\n", - "'MM401':[['11####1', 0], ['1#1###1', 0], ['###1##1', 0], ['1#10###', 0], ['##1111#', 0], ['11#0###', 0], ['1##01##', 0], ['1#1#11#', 0], ['1###1#1', 0], ['0###0#0', 1], ['0#0###0', 1], ['#0000##', 1], ['0####00', 1], ['###10#0', 1], ['###1#00', 1], ['#00#0#0', 1], ['##01##0', 1], ['0##0###', 1]],\n", + "automata_output_list = {\n", + " 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", + " 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", + " 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", + " 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'DMC' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'COE_1' : ['0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1'],\n", + " 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", + " 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", "}\n", "\n", - "gkl_node = BooleanNode.from_partial_lut(automata['GKL'])\n", - "print(gkl_node.outputs)\n", - "print(gkl_node.bias())\n" + "\n", + "for output in automata_output_list:\n", + " node = BooleanNode.from_output_list(outputs=automata_output_list[output])\n", + " print(f\"Bias of {output} = {node.bias()}\")" ] }, { - "cell_type": "code", - "execution_count": 17, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "GKL_INCOMPLETE = [['0###0#0', 0], ['##0#0#0', 0], ['###10#0', 0], ['##00###', 0], ['1#1###1', 1], ['###1##1', 1], ['###11##', 1],['1#1#1##', 1],] #,['1#10###', 1] ['0##0###', 0]\n", - "\n", - "node = BooleanNode.from_partial_lut(GKL_INCOMPLETE, verbose=True)\n", - "print(node.outputs)\n", - "\n", - "# node = node.BooleanNode.from_partial_lut(GKL_INCOMPLETE, fill_missing_output_randomly=True)\n", - "node = node.generate_with_required_bias(required_node_bias=0.5, limit=100, verbose=True)\n", - "print(node[0].outputs)" + "## Effective graphs of the sample automata" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bias of GKL = 0.5\n", + "Bias of GP = 0.5\n", + "Bias of GEP_1 = 0.5\n", + "Bias of GEP_2 = 0.5\n", + "Bias of Das = 0.5\n", + "Bias of Davis = 0.5\n", + "Bias of ABK = 0.5\n", + "Bias of DMC = 0.4921875\n", + "Bias of COE_1 = 0.515625\n", + "Bias of COE_2 = 0.5\n", + "Bias of MM401 = 0.5\n" + ] + } + ], + "source": [ + "# effective graphs of automata\n", + "automata = {\n", + " \"GKL\": [[\"0###0#0\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"1#1###1\", 1],[\"###1##1\", 1],[\"###11##\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1],],\n", + " \"GP\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"0#0#0##\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],],\n", + " \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"00#1###\", 0],[\"1#1###1\", 1],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],],\n", + " \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"#0#00##\", 0],[\"11####1\", 1],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],],\n", + " \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],[\"##11###\", 1],],\n", + " \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],[\"1#10#0#\", 1],],\n", + " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"0#0#0##\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],],\n", + " \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"1#00101\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],[\"#011000\", 1],],\n", + " \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],[\"##1001#\", 1],],\n", + " \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],[\"1#1##01\", 1],],\n", + " \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1##01##\", 0],[\"1#1#11#\", 0],[\"1###1#1\", 0],[\"0###0#0\", 1],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1],[\"0##0###\", 1],],\n", + "}\n", + "# for node in automata:\n", + "# generated_node = BooleanNode.from_partial_lut(automata[node])\n", + "# print(f\"Bias of {node} = {generated_node.bias()}\")" + ] + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "# # plot_schemata(GKL_NODE)\n", - "# gkl_lut= MM401_NODE.schemata_look_up_table()\n", - "# gkl = [list(item) for item in zip(gkl_lut['Input'].tolist(), gkl_lut['Output'].tolist())]\n", - "# print(gkl)\n", - "# # gkl_lut" + "Removing lines of the effective graph to make the automata incomplete, to regenerate the complete LUT from this and verify that the function works correctly. " ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "128" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "partial_lut= GKL.copy()\n", - "all_states = dict(partial_lut)\n", - "for entry in partial_lut:\n", - " # print(entry[0])\n", - " if not all([x in [\"0\", \"1\", \"-\", \"#\", \"2\", \"x\"] for x in entry[0]]):\n", - " raise ValueError(\n", - " \"All the input entries of the partial LUT must be valid binary strings.\"\n", - " )\n", - "\n", - " elif any([x in [\"-\", \"#\", \"2\", \"x\"] for x in entry[0]]):\n", - " missing_data_indices = [i for i, x in enumerate(entry[0]) if x in [\"-\", \"#\", \"2\", \"x\"]]\n", - " table = []\n", - " output_list_permutations = []\n", - "\n", - " for i in range(2 ** len(missing_data_indices)):\n", - " row = [int(x) for x in bin(i)[2:].zfill(len(missing_data_indices))]\n", - " table.append(row)\n", - " output_list_permutations.append(entry[0])\n", - " for j in range(len(missing_data_indices)):\n", - " output_list_permutations[i] = (\n", - " output_list_permutations[i][: missing_data_indices[j]]\n", - " + str(table[i][j])\n", - " + output_list_permutations[i][missing_data_indices[j] + 1 :]\n", - " )\n", - "\n", - " \n", - " del all_states[entry[0]]\n", - "\n", - " for perm in output_list_permutations:\n", - " if perm in all_states and all_states[perm] != entry[1]:\n", - " print(\"Clashing output values for entry:\", perm)\n", - " all_states[perm] = \"!\"\n", - " else:\n", - " all_states[perm] = entry[1]\n", - "k = len(partial_lut[0][0])\n", - "for i in range(2**k):\n", - " state = bin(i)[2:].zfill(k)\n", - " if state not in all_states:\n", - " all_states[state] = \"?\"\n", - "\n", - "all_states = sorted(all_states.items(), key=lambda x: x[0])\n", - "len(all_states)" + "# removing some effective graph inputs to make them incomplete\n", + "incomplete_automata = {\n", + " # \"GKL\": [[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"###1##1\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1], [\"1#1###1\", 1],], # [\"0###0#0\", 0], [\"###11##\", 1], is missing\n", + " \"GP\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],], # [\"0#0#00#\", 0], is missing\n", + " # \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],], # [\"00#1###\", 0],[\"1#1###1\", 1], are missing\n", + " # \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],], # [\"#0#00##\", 0],[\"11####1\", 1], are missing\n", + " # \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],], # [\"##11###\", 1], is missing\n", + " # \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],], # [\"1#10#0#\", 1], is missing\n", + " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],], # [\"0#0#0##\", 0],[\"###01#1\", 1], is missing\n", + " # \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],], # [\"1#00101\", 0],[\"#011000\", 1], is missing\n", + " # \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],], # [\"##1001#\", 1], is missing\n", + " # \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],], # [\"1#1##01\", 1], is missing\n", + " # \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1#1#11#\", 0],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1], [\"1###1#1\", 0],[\"0##0###\", 1], ], # [\"1##01##\", 0],[\"0###0#0\", 1],are missing\n", + "}\n", + "\n", + "automata_output_list = {\n", + " 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", + " 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " # 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " # 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", + " # 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", + " # 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " # 'DMC' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1'],\n", + " # 'COE_1' : ['0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1'],\n", + " # 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", + " # 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", + "}\n", + "\n", + "for automata in incomplete_automata:\n", + " node = None\n", + " generated_node_permuations = None\n", + " node = BooleanNode.from_partial_lut(incomplete_automata[automata])\n", + " '''print(f\"Count of '?' {node.outputs.count('?')}\")\n", + " print(f\"Count of '1' {node.outputs.count('1')}\")\n", + " print(f\"Count of '0' {node.outputs.count('0')}\")\n", + " # indices where the output is '?'\n", + " indices = [i for i, x in enumerate(node.outputs) if x == \"?\"]\n", + " print(f\"Indices of '?' {indices}\")'''\n", + "\n", + " generated_node_permuations = BooleanNode.generate_with_required_bias( node, required_node_bias=0.5, verbose=True)\n", + " list_of_output_lists = [node.outputs for node in generated_node_permuations]\n", + "\n", + " # print(automata)\n", + "\n", + " #checking if original rule is contained in the list of generated rules, to verify if the function is working correctly\n", + " if automata_output_list[automata] in list_of_output_lists:\n", + " print(\"Found a match\")\n", + " else:\n", + " print(\"No match found\")\n", + "\n", + "\n", + " # # find the list in list_of_output_lists that matches automata_output_list[automata]\n", + " # print(\"Index : \", list_of_output_lists.index(automata_output_list[automata]))" ] } ], From f0e615fe916b06e67ea2d17f447e679a19444278 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 24 Jun 2024 19:58:42 -0400 Subject: [PATCH 11/14] converted lists into generator for faster computation --- cana/boolean_node.py | 70 ++++++++++---- tutorials/Generating from Partial LUTs.ipynb | 98 ++++++++++---------- 2 files changed, 105 insertions(+), 63 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index 5172fd1..aac3cfa 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -1081,6 +1081,7 @@ def generate_with_required_bias( ["1"] * ones_to_be_generated + ["0"] * (number_of_missing_values - ones_to_be_generated) ) # creating a list of 1 and 0 to replace the '?' with the right ratio required to achieve the required bias. + combinationsnumber = comb(number_of_missing_values, ones_to_be_generated) if combinationsnumber > limit: @@ -1088,29 +1089,66 @@ def generate_with_required_bias( f"Total possible permutaions = {combinationsnumber}. Selecting {limit} permutations randomly." ) # create a list of all possible unique arrangements of the missing output values - combinations = list(islice(set(permutations(missing_output_values)), limit)) - - generated_node_permutations = [None] * len(combinations) - - for count, combination in enumerate(combinations): - combination = list(combination) - # random.shuffle(combination) # shuffling the combination creates duplicates and misses some combinations. - generated_outputs = generated_node.outputs.copy() - for i, output in enumerate(generated_node.outputs): - if output == "?": - generated_outputs[i] = combination.pop() - generated_node_permutations[count] = BooleanNode.from_output_list( - generated_outputs, *args, **kwargs - ) # generating a list of nodes with all possible permutations of the missing output values that achieve the required bias. + # combinations = list(islice(set(permutations(missing_output_values)), limit)) + def unique_permutations_missing_values(elements, n): + """ + Generate n unique permutations of elements. + """ + seen = set() + elements = list(elements) # Ensure we can shuffle + random.shuffle(elements) # Shuffle to ensure randomness in subsets + for perm in permutations(elements): + perm_as_str = str(perm) # Convert to string for hashability + if perm_as_str not in seen: + seen.add(perm_as_str) + yield perm + if len(seen) == n: + return + + combinations = unique_permutations_missing_values( + missing_output_values, combinationsnumber + ) + generated_node_permutations = [None] * combinationsnumber + + def node_permutations(combinations, node_outputs, *args, **kwargs): + for combination in combinations: + combination = list(combination) + generated_outputs = node_outputs.copy() + for i, output in enumerate(node_outputs): + if output == "?": + generated_outputs[i] = combination.pop() + yield BooleanNode.from_output_list( + generated_outputs, *args, **kwargs + ) + + generated_node_permutations = node_permutations( + combinations, generated_node.outputs, *args, **kwargs + ) + # generated_node_permutations = [None] * combinationsnumber + + # for count, combination in enumerate(combinations): + # combination = list(combination) + # # random.shuffle(combination) # shuffling the combination creates duplicates and misses some combinations. + # generated_outputs = generated_node.outputs.copy() + # for i, output in enumerate(generated_node.outputs): + # if output == "?": + # generated_outputs[i] = combination.pop() + # generated_node_permutations[count] = BooleanNode.from_output_list( + # generated_outputs, *args, **kwargs + # ) # generating a list of nodes with all possible permutations of the missing output values that achieve the required bias. + + output_bias_for_print = ( + ones_to_be_generated + current_ones + ) / 2**generated_node.k # for the print message in the end if verbose: if min: print( - f"Generated {len(generated_node_permutations)} node(s) with a bias of {generated_node_permutations[0].bias(verbose=False)}. This is the closest achievable bias to the required bias of {bias}." + f"Generated {combinationsnumber} node(s) with a bias of {output_bias_for_print}. This is the closest achievable bias to the required bias of {bias}." ) else: print( - f"Generated {len(generated_node_permutations)} node(s) with a bias of {generated_node_permutations[0].bias(verbose=False)}. This is the closest bias less than or equal to the required bias of {bias}." + f"Generated {combinationsnumber} node(s) with a bias of {output_bias_for_print}. This is the closest bias less than or equal to the required bias of {bias}." ) return generated_node_permutations # returning a list of BooleanNode objects with the required bias. diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index f209ec6..35a6de2 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -332,8 +332,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "['0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0']\n" + "\n", + "['0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0']\n" ] } ], @@ -396,11 +396,11 @@ "\n", "for lut in partial_luts:\n", " node = None\n", - " generated_node_permuations = None\n", + " generated_node_permutations = None\n", " node = BooleanNode.from_partial_lut(lut)\n", " # print(node.outputs)\n", "\n", - " generated_node_permuations = node.generate_with_required_bias(\n", + " generated_node_permutations = node.generate_with_required_bias(\n", " required_node_bias=0.49, limit=1000, verbose=True\n", " )\n", " # print(generated_node_permuations[0].outputs, \"\\n\")\n", @@ -593,25 +593,7 @@ "cell_type": "code", "execution_count": 10, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Bias of GKL = 0.5\n", - "Bias of GP = 0.5\n", - "Bias of GEP_1 = 0.5\n", - "Bias of GEP_2 = 0.5\n", - "Bias of Das = 0.5\n", - "Bias of Davis = 0.5\n", - "Bias of ABK = 0.5\n", - "Bias of DMC = 0.4921875\n", - "Bias of COE_1 = 0.515625\n", - "Bias of COE_2 = 0.5\n", - "Bias of MM401 = 0.5\n" - ] - } - ], + "outputs": [], "source": [ "# effective graphs of automata\n", "automata = {\n", @@ -622,8 +604,8 @@ " \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],[\"##11###\", 1],],\n", " \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],[\"1#10#0#\", 1],],\n", " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"0#0#0##\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],],\n", - " \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"1#00101\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],[\"#011000\", 1],],\n", - " \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],[\"##1001#\", 1],],\n", + " # \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"1#00101\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],[\"#011000\", 1],],\n", + " # \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],[\"##1001#\", 1],],\n", " \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],[\"1#1##01\", 1],],\n", " \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1##01##\", 0],[\"1#1#11#\", 0],[\"1###1#1\", 0],[\"0###0#0\", 1],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1],[\"0##0###\", 1],],\n", "}\n", @@ -641,42 +623,67 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 70 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 70 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n", + "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "Found a match\n" + ] + } + ], "source": [ "# removing some effective graph inputs to make them incomplete\n", "incomplete_automata = {\n", - " # \"GKL\": [[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"###1##1\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1], [\"1#1###1\", 1],], # [\"0###0#0\", 0], [\"###11##\", 1], is missing\n", + " \"GKL\": [[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"###1##1\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1], [\"1#1###1\", 1],], # [\"0###0#0\", 0], [\"###11##\", 1], is missing\n", " \"GP\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],], # [\"0#0#00#\", 0], is missing\n", - " # \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],], # [\"00#1###\", 0],[\"1#1###1\", 1], are missing\n", - " # \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],], # [\"#0#00##\", 0],[\"11####1\", 1], are missing\n", - " # \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],], # [\"##11###\", 1], is missing\n", - " # \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],], # [\"1#10#0#\", 1], is missing\n", + " \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],], # [\"00#1###\", 0],[\"1#1###1\", 1], are missing\n", + " \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],], # [\"#0#00##\", 0],[\"11####1\", 1], are missing\n", + " \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],], # [\"##11###\", 1], is missing\n", + " \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],], # [\"1#10#0#\", 1], is missing\n", " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],], # [\"0#0#0##\", 0],[\"###01#1\", 1], is missing\n", " # \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],], # [\"1#00101\", 0],[\"#011000\", 1], is missing\n", " # \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],], # [\"##1001#\", 1], is missing\n", - " # \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],], # [\"1#1##01\", 1], is missing\n", - " # \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1#1#11#\", 0],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1], [\"1###1#1\", 0],[\"0##0###\", 1], ], # [\"1##01##\", 0],[\"0###0#0\", 1],are missing\n", + " \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],], # [\"1#1##01\", 1], is missing\n", + " \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1#1#11#\", 0],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1], [\"1###1#1\", 0],[\"0##0###\", 1], ], # [\"1##01##\", 0],[\"0###0#0\", 1],are missing\n", "}\n", "\n", "automata_output_list = {\n", " 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", " 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " # 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " # 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", - " # 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", - " # 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", + " 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", + " 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", + " 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", " 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", " # 'DMC' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1'],\n", " # 'COE_1' : ['0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1'],\n", - " # 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", - " # 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", + " 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", + " 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", "}\n", "\n", "for automata in incomplete_automata:\n", " node = None\n", - " generated_node_permuations = None\n", + " generated_node_permutations = None\n", " node = BooleanNode.from_partial_lut(incomplete_automata[automata])\n", " '''print(f\"Count of '?' {node.outputs.count('?')}\")\n", " print(f\"Count of '1' {node.outputs.count('1')}\")\n", @@ -685,8 +692,8 @@ " indices = [i for i, x in enumerate(node.outputs) if x == \"?\"]\n", " print(f\"Indices of '?' {indices}\")'''\n", "\n", - " generated_node_permuations = BooleanNode.generate_with_required_bias( node, required_node_bias=0.5, verbose=True)\n", - " list_of_output_lists = [node.outputs for node in generated_node_permuations]\n", + " generated_node_permutations = BooleanNode.generate_with_required_bias( node, required_node_bias=0.5, verbose=True)\n", + " list_of_output_lists = [node.outputs for node in generated_node_permutations]\n", "\n", " # print(automata)\n", "\n", @@ -695,10 +702,7 @@ " print(\"Found a match\")\n", " else:\n", " print(\"No match found\")\n", - "\n", - "\n", - " # # find the list in list_of_output_lists that matches automata_output_list[automata]\n", - " # print(\"Index : \", list_of_output_lists.index(automata_output_list[automata]))" + "\n" ] } ], From 3a99b8f3e58dab6e02797b7326c2586254d45793 Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Mon, 24 Jun 2024 20:01:12 -0400 Subject: [PATCH 12/14] modified description --- cana/boolean_node.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index aac3cfa..c8ce37d 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -1014,10 +1014,11 @@ def generate_with_required_bias( Args: required_node_bias (float) : The required node bias to fill the missing output values with. + limit (int) : The maximum number of permutations to generate. If the total number of permutations is greater than the limit, then a random subset of the permutations is generated. verbose (bool) : If True, print additional information. Returns: - List of BooleanNode objects with the required bias. + A Generator of BooleanNode objects with the required bias. Example: >>> BooleanNode.generate_with_required_bias(required_node_bias=0.5, verbose=True, name="EG") @@ -1025,7 +1026,6 @@ def generate_with_required_bias( Note: The required node bias should be a float value between 0 and 1. - # TODO : [SRI] check why when run in a notebook does the cell take so long to run. It says pending. and takes forever to initialize and the runtime when finished is close to zero. """ generated_node = self bias = required_node_bias # making a copy for print statement at the end of function @@ -1125,19 +1125,6 @@ def node_permutations(combinations, node_outputs, *args, **kwargs): combinations, generated_node.outputs, *args, **kwargs ) - # generated_node_permutations = [None] * combinationsnumber - - # for count, combination in enumerate(combinations): - # combination = list(combination) - # # random.shuffle(combination) # shuffling the combination creates duplicates and misses some combinations. - # generated_outputs = generated_node.outputs.copy() - # for i, output in enumerate(generated_node.outputs): - # if output == "?": - # generated_outputs[i] = combination.pop() - # generated_node_permutations[count] = BooleanNode.from_output_list( - # generated_outputs, *args, **kwargs - # ) # generating a list of nodes with all possible permutations of the missing output values that achieve the required bias. - output_bias_for_print = ( ones_to_be_generated + current_ones ) / 2**generated_node.k # for the print message in the end From 46c6df89ef4624153f170c5b35754b9489d955ce Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Wed, 26 Jun 2024 01:54:43 -0400 Subject: [PATCH 13/14] added generator to bias function. added tests. --- cana/boolean_node.py | 25 +- cana/utils.py | 1 - tests/test_boolean_node.py | 39 ++- tutorials/Generating from Partial LUTs.ipynb | 251 ++++--------------- 4 files changed, 96 insertions(+), 220 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index c8ce37d..924f72a 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -15,7 +15,7 @@ # MIT license. from __future__ import division -from itertools import combinations, compress, islice, product, permutations +from itertools import combinations, compress, product, permutations from statistics import mean import networkx as nx @@ -975,7 +975,6 @@ def from_partial_lut( The partial look-up table should be a list of tuples where each tuple contains a binary input state and the corresponding output value. For example, [('00', 0), ('01', 1), ('11', 1)]. The fill_missing_output_randomly should be a boolean value. - # TODO : [SRI] add tests for this """ generated_lut = fill_out_lut(partial_lut, verbose=False) @@ -1003,7 +1002,7 @@ def from_partial_lut( def generate_with_required_bias( self, required_node_bias=None, - limit=1000, + # limit=1000, verbose=False, *args, **kwargs, @@ -1084,10 +1083,10 @@ def generate_with_required_bias( combinationsnumber = comb(number_of_missing_values, ones_to_be_generated) - if combinationsnumber > limit: - warnings.warn( - f"Total possible permutaions = {combinationsnumber}. Selecting {limit} permutations randomly." - ) + # if combinationsnumber > limit: + # warnings.warn( + # f"Total possible permutaions = {combinationsnumber}. Selecting {limit} permutations randomly." + # ) # create a list of all possible unique arrangements of the missing output values # combinations = list(islice(set(permutations(missing_output_values)), limit)) def unique_permutations_missing_values(elements, n): @@ -1095,9 +1094,11 @@ def unique_permutations_missing_values(elements, n): Generate n unique permutations of elements. """ seen = set() - elements = list(elements) # Ensure we can shuffle - random.shuffle(elements) # Shuffle to ensure randomness in subsets + # elements = list(elements) # Ensure we can shuffle + # random.shuffle(elements) # Shuffle to ensure randomness in subsets for perm in permutations(elements): + perm = list(perm) + random.shuffle(perm) # Shuffle to ensure randomness in subsets perm_as_str = str(perm) # Convert to string for hashability if perm_as_str not in seen: seen.add(perm_as_str) @@ -1108,7 +1109,7 @@ def unique_permutations_missing_values(elements, n): combinations = unique_permutations_missing_values( missing_output_values, combinationsnumber ) - generated_node_permutations = [None] * combinationsnumber + generated_node_permutations = [] def node_permutations(combinations, node_outputs, *args, **kwargs): for combination in combinations: @@ -1131,11 +1132,11 @@ def node_permutations(combinations, node_outputs, *args, **kwargs): if verbose: if min: print( - f"Generated {combinationsnumber} node(s) with a bias of {output_bias_for_print}. This is the closest achievable bias to the required bias of {bias}." + f"{combinationsnumber:.2e} possible permutation(s) with a bias of {output_bias_for_print}. This is the closest achievable bias to the required bias of {bias}." ) else: print( - f"Generated {combinationsnumber} node(s) with a bias of {output_bias_for_print}. This is the closest bias less than or equal to the required bias of {bias}." + f"{combinationsnumber:.2e} possible permutation(s) with a bias of {output_bias_for_print}. This is the closest bias less than or equal to the required bias of {bias}." ) return generated_node_permutations # returning a list of BooleanNode objects with the required bias. diff --git a/cana/utils.py b/cana/utils.py index dcbcd9b..79fa0de 100644 --- a/cana/utils.py +++ b/cana/utils.py @@ -348,7 +348,6 @@ def fill_out_lut(partial_lut, verbose=False): [('00', 0), ('01', 0), ('10', 1), ('11', 1)] # TODO: [SRI] generate LUT from two symbol schemata, with a specified ratio of wildcard symbols - # TODO: [SRI] add tests for canonical rule logic, rule 90, rule 110 # TODO: [SRI] use examples COSA rule, GKL rule where you fill up LUT based on the annihilation inputs and see if it matches with the rules plus bias. """ diff --git a/tests/test_boolean_node.py b/tests/test_boolean_node.py index 94ba86a..f306f3c 100644 --- a/tests/test_boolean_node.py +++ b/tests/test_boolean_node.py @@ -859,7 +859,44 @@ def test_generate_with_required_node_bias(): "ABK": [["0#01###", 0],["0##10##", 0],["0#####0", 0],["###0##0", 0],["##1#1#1", 1],["1#####1", 1],["1##1###", 1],["##10##1", 1],], # ["0#0#0##", 0],["###01#1", 1], is missing } - + automata = { + "GKL": [ + ["0###0#0", 0], + ["##0#0#0", 0], + ["###10#0", 0], + ["##00###", 0], + ["0##0###", 0], + ["1#1###1", 1], + ["###1##1", 1], + ["###11##", 1], + ["1#10###", 1], + ["1#1#1##", 1], + ], + "GP": [ + ["0#01###", 0], + ["0##10##", 0], + ["0#####0", 0], + ["###0##0", 0], + ["0#0#0##", 0], + ["##1#1#1", 1], + ["1#####1", 1], + ["1##1###", 1], + ["##10##1", 1], + ["###01#1", 1], + ], + "ABK": [ + ["0#01###", 0], + ["0##10##", 0], + ["0#####0", 0], + ["###0##0", 0], + ["0#0#0##", 0], + ["##1#1#1", 1], + ["1#####1", 1], + ["1##1###", 1], + ["##10##1", 1], + ["###01#1", 1], + ], + } automata_output_list = { 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'], 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'], diff --git a/tutorials/Generating from Partial LUTs.ipynb b/tutorials/Generating from Partial LUTs.ipynb index 35a6de2..f598c4a 100644 --- a/tutorials/Generating from Partial LUTs.ipynb +++ b/tutorials/Generating from Partial LUTs.ipynb @@ -296,15 +296,15 @@ "source": [ "# example partial look up tables\n", "partial_luts = [\n", - " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", - " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", - " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", - " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", - " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", - " [(\"-1--\", \"0\")],\n", - " [(\"-1--\", \"1\")],\n", - " [(\"-1--\", \"?\")],\n", + " [(\"001-\", \"0\"), (\"1--1\", \"1\"), (\"11--\", \"1\")],\n", + " [(\"00--\", \"0\"), (\"1--1\", \"1\"), (\"110-\", \"1\")],\n", + " [(\"1--\", \"1\"), (\"101\", \"0\"), (\"011\", \"0\"), (\"01-\", \"1\")], # will have clashes\n", + " [(\"0--0\", \"0\"), (\"1--1\", \"0\"), (\"0111\", \"1\"), (\"0011\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"1\")],\n", + " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", + " [(\"-1--\", \"0\")],\n", + " [(\"-1--\", \"1\")],\n", + " [(\"-1--\", \"?\")],\n", "]\n", "\n", "# using the from_partial_lut function found in BooleanNode class\n", @@ -332,8 +332,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "['0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0']\n" + "\n", + "['0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0']\n" ] } ], @@ -369,14 +369,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "Generated 8 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 21 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 6 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 35 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 126 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 8 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 220 node(s) with a bias of 0.4375. This is the closest bias less than or equal to the required bias of 0.49.\n", - "Generated 56 node(s) with a bias of 0.375. This is the closest bias less than or equal to the required bias of 0.49.\n" + "28 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "35 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "1 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "35 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "84 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "1 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "495 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", + "70 possible permutation(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n" ] } ], @@ -390,21 +390,41 @@ " [(\"1-01\", \"1\"), (\"1-1-\", \"0\"), (\"0110\", \"0\"), (\"01-1\", \"?\")],\n", " [(\"-1--\", \"0\")],\n", " [(\"-10-\", \"1\")],\n", - " [(\"11-\",\"?\")]\n", + " [(\"11-\", \"?\")],\n", "]\n", "\n", "\n", "for lut in partial_luts:\n", " node = None\n", - " generated_node_permutations = None\n", + " # generated_node_permutations = None\n", " node = BooleanNode.from_partial_lut(lut)\n", " # print(node.outputs)\n", "\n", " generated_node_permutations = node.generate_with_required_bias(\n", - " required_node_bias=0.49, limit=1000, verbose=True\n", + " required_node_bias=0.5, limit=50, verbose=True\n", " )\n", - " # print(generated_node_permuations[0].outputs, \"\\n\")\n", - "\n" + " # print(generated_node_permuations[0].outputs, \"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['1', '1', '0', '0', '0', '0', '1', '1']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "node = next(generated_node_permutations)\n", + "node.outputs" ] }, { @@ -432,7 +452,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -523,187 +543,6 @@ "ValueError: Only one of required_effective_connectvity, required_node_bias and fill_missing_output_randomly can be True. Please set the rest to False.\n", "```" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## automata rules samples" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## list of DCT automata" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Bias of GKL = 0.5\n", - "Bias of GP = 0.5\n", - "Bias of GEP_1 = 0.5\n", - "Bias of GEP_2 = 0.5\n", - "Bias of Davis = 0.5\n", - "Bias of Das = 0.5\n", - "Bias of ABK = 0.5\n", - "Bias of DMC = 0.4921875\n", - "Bias of COE_1 = 0.515625\n", - "Bias of COE_2 = 0.5\n", - "Bias of MM401 = 0.5\n" - ] - } - ], - "source": [ - "automata_output_list = {\n", - " 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", - " 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", - " 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", - " 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'DMC' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'COE_1' : ['0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1'],\n", - " 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", - " 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", - "}\n", - "\n", - "\n", - "for output in automata_output_list:\n", - " node = BooleanNode.from_output_list(outputs=automata_output_list[output])\n", - " print(f\"Bias of {output} = {node.bias()}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Effective graphs of the sample automata" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# effective graphs of automata\n", - "automata = {\n", - " \"GKL\": [[\"0###0#0\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"1#1###1\", 1],[\"###1##1\", 1],[\"###11##\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1],],\n", - " \"GP\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"0#0#0##\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],],\n", - " \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"00#1###\", 0],[\"1#1###1\", 1],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],],\n", - " \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"#0#00##\", 0],[\"11####1\", 1],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],],\n", - " \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],[\"##11###\", 1],],\n", - " \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],[\"1#10#0#\", 1],],\n", - " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"0#0#0##\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],],\n", - " # \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"1#00101\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],[\"#011000\", 1],],\n", - " # \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],[\"##1001#\", 1],],\n", - " \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],[\"1#1##01\", 1],],\n", - " \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1##01##\", 0],[\"1#1#11#\", 0],[\"1###1#1\", 0],[\"0###0#0\", 1],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1],[\"0##0###\", 1],],\n", - "}\n", - "# for node in automata:\n", - "# generated_node = BooleanNode.from_partial_lut(automata[node])\n", - "# print(f\"Bias of {node} = {generated_node.bias()}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Removing lines of the effective graph to make the automata incomplete, to regenerate the complete LUT from this and verify that the function works correctly. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 70 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 70 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n", - "Generated 1 node(s) with a bias of 0.5. This is the closest bias less than or equal to the required bias of 0.5.\n", - "Found a match\n" - ] - } - ], - "source": [ - "# removing some effective graph inputs to make them incomplete\n", - "incomplete_automata = {\n", - " \"GKL\": [[\"##0#0#0\", 0],[\"###10#0\", 0],[\"##00###\", 0],[\"0##0###\", 0],[\"###1##1\", 1],[\"1#10###\", 1],[\"1#1#1##\", 1], [\"1#1###1\", 1],], # [\"0###0#0\", 0], [\"###11##\", 1], is missing\n", - " \"GP\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###01#1\", 1],], # [\"0#0#00#\", 0], is missing\n", - " \"GEP_1\": [[\"000##0#\", 0],[\"0###0#0\", 0],[\"0##10##\", 0],[\"0#0#00#\", 0],[\"###0##0\", 0],[\"00####0\", 0],[\"##00#0#\", 0],[\"#11#1#1\", 1],[\"#1#11##\", 1],[\"1####11\", 1],[\"#1##111\", 1],[\"1##1###\", 1],[\"##10##1\", 1],[\"###0#11\", 1],], # [\"00#1###\", 0],[\"1#1###1\", 1], are missing\n", - " \"GEP_2\": [[\"0#0###0\", 0],[\"0####00\", 0],[\"#0##000\", 0],[\"###1#00\", 0],[\"#00#0#0\", 0],[\"##01##0\", 0],[\"0##0###\", 0],[\"111##1#\", 1],[\"###1##1\", 1],[\"11#0###\", 1],[\"1##01##\", 1],[\"1#1#11#\", 1],[\"1###1#1\", 1],[\"##11#1#\", 1],], # [\"#0#00##\", 0],[\"11####1\", 1], are missing\n", - " \"Das\": [[\"000##00\", 0],[\"#010#00\", 0],[\"0#01###\", 0],[\"###00##\", 0],[\"#001###\", 0],[\"0#0#0##\", 0],[\"##0#00#\", 0],[\"##01#0#\", 0],[\"00#0#00\", 0],[\"#00#0##\", 0],[\"##011#0\", 0],[\"##1#11#\", 1],[\"11#101#\", 1],[\"###01#1\", 1],[\"#1#01##\", 1],[\"###011#\", 1],[\"#11#1##\", 1],[\"##1#1#1\", 1],[\"11#1#11\", 1],[\"1#001##\", 1],[\"11##111\", 1],], # [\"##11###\", 1], is missing\n", - " \"Davis\": [[\"#10#0#0\", 0],[\"00#00##\", 0],[\"##110#0\", 0],[\"#00#0#1\", 0],[\"10#011#\", 0],[\"01##010\", 0],[\"###1000\", 0],[\"00#0#0#\", 0],[\"00##000\", 0],[\"#1#100#\", 0],[\"001#0#0\", 0],[\"0#1#010\", 0],[\"##0#00#\", 0],[\"#1#10#0\", 0],[\"##00###\", 0],[\"0##001#\", 0],[\"#1#1#11\", 1],[\"#011##1\", 1],[\"0#1#11#\", 1],[\"#110#0#\", 1],[\"101#0#1\", 1],[\"111##11\", 1],[\"#001#10\", 1],[\"101##01\", 1],[\"1#1#10#\", 1],[\"1110###\", 1],[\"##11#11\", 1],[\"#11#1##\", 1],[\"1#100##\", 1],[\"1#1#011\", 1],[\"###11##\", 1],], # [\"1#10#0#\", 1], is missing\n", - " \"ABK\": [[\"0#01###\", 0],[\"0##10##\", 0],[\"0#####0\", 0],[\"###0##0\", 0],[\"##1#1#1\", 1],[\"1#####1\", 1],[\"1##1###\", 1],[\"##10##1\", 1],], # [\"0#0#0##\", 0],[\"###01#1\", 1], is missing\n", - " # \"DMC\": [[\"00##01#\", 0],[\"0#0###0\", 0],[\"1011#01\", 0],[\"01##000\", 0],[\"#110001\", 0],[\"#01#010\", 0],[\"#0#00#0\", 0],[\"#111000\", 0],[\"0#01#1#\", 0],[\"1#10100\", 0],[\"101110#\", 0],[\"#0110#1\", 0],[\"00##0#1\", 0],[\"0##00##\", 0],[\"##00000\", 0],[\"#0##100\", 0],[\"#010##0\", 0],[\"00#0##0\", 0],[\"#0000##\", 0],[\"0#0#0##\", 0],[\"0101###\", 0],[\"#01101#\", 0],[\"0##1100\", 0],[\"#0#0#00\", 0],[\"1000#0#\", 0],[\"#00##00\", 0],[\"01#1#00\", 0],[\"###0111\", 1],[\"1#0#11#\", 1],[\"01101##\", 1],[\"11###1#\", 1],[\"110#0#1\", 1],[\"#11#11#\", 1],[\"#111#1#\", 1],[\"0#1#1#1\", 1],[\"1101###\", 1],[\"1#01#1#\", 1],[\"1##111#\", 1],[\"##1#111\", 1],[\"1#01##1\", 1],[\"00##101\", 1],[\"110#1#0\", 1],[\"##101#1\", 1],[\"1#10#11\", 1],[\"#11#1#1\", 1],[\"1###111\", 1],[\"11#11##\", 1],[\"1010##1\", 1],[\"##1111#\", 1],[\"0##01#1\", 1],[\"#111##1\", 1],[\"#001101\", 1],[\"11100#0\", 1],[\"11#1##1\", 1],], # [\"1#00101\", 0],[\"#011000\", 1], is missing\n", - " # \"COE_1\": [[\"01010##\", 0],[\"00#01#0\", 0],[\"#00#001\", 0],[\"00#0#0#\", 0],[\"#1#0110\", 0],[\"01##000\", 0],[\"#000##0\", 0],[\"0#0#0#0\", 0],[\"#00#1#0\", 0],[\"0#00#0#\", 0],[\"1#11#00\", 0],[\"00101##\", 0],[\"000###0\", 0],[\"#0000##\", 0],[\"##11010\", 0],[\"0#00##0\", 0],[\"#0#1100\", 0],[\"#1#1000\", 0],[\"0##0110\", 0],[\"#00111#\", 0],[\"00##100\", 0],[\"##11100\", 0],[\"1#0#110\", 0],[\"#10010#\", 0],[\"#1#0101\", 0],[\"0##000#\", 0],[\"1#110#0\", 0],[\"101100#\", 0],[\"0#0#00#\", 0],[\"##001#0\", 0],[\"0##1010\", 0],[\"01#10#0\", 0],[\"10#1001\", 0],[\"#111#00\", 0],[\"#1110#0\", 0],[\"0##0#01\", 0],[\"11###11\", 1],[\"001100#\", 1],[\"101#11#\", 1],[\"110#01#\", 1],[\"1##1011\", 1],[\"01011##\", 1],[\"10##101\", 1],[\"##1#011\", 1],[\"###1101\", 1],[\"11##0#1\", 1],[\"#1#0#11\", 1],[\"#1#11#1\", 1],[\"10#01#1\", 1],[\"#11##11\", 1],[\"##1111#\", 1],[\"#111##1\", 1],[\"101#1#1\", 1],[\"01#111#\", 1],[\"1#0101#\", 1],[\"#1##111\", 1],[\"1#100##\", 1],[\"1#10#00\", 1],[\"##111#1\", 1],[\"10010#0\", 1],[\"#0#1011\", 1],[\"#110100\", 1],[\"1010###\", 1],[\"11#00##\", 1],[\"##11#11\", 1],[\"#10110#\", 1],[\"11#1##1\", 1],[\"1#1##11\", 1],[\"##00111\", 1],[\"1##0111\", 1],[\"0#11##1\", 1],], # [\"##1001#\", 1], is missing\n", - " \"COE_2\": [[\"00#011#\", 0],[\"00#01#0\", 0],[\"0#0###0\", 0],[\"0##0111\", 0],[\"001#11#\", 0],[\"100#00#\", 0],[\"##0110#\", 0],[\"00#0#00\", 0],[\"00101##\", 0],[\"#1#001#\", 0],[\"##01#00\", 0],[\"00##110\", 0],[\"01#0#11\", 0],[\"1001#0#\", 0],[\"#001##0\", 0],[\"0100###\", 0],[\"#1##010\", 0],[\"##0#0#0\", 0],[\"###10#0\", 0],[\"00##000\", 0],[\"00#000#\", 0],[\"#1000##\", 0],[\"0010#0#\", 0],[\"0#0011#\", 0],[\"##0000#\", 0],[\"010#1##\", 0],[\"00#1#10\", 0],[\"#00##00\", 0],[\"#11##01\", 1],[\"1##1#11\", 1],[\"##110#1\", 1],[\"0##10#1\", 1],[\"11#01##\", 1],[\"1#10#0#\", 1],[\"1#1#1##\", 1],[\"#1#10#1\", 1],[\"#1111##\", 1],[\"#001#11\", 1],[\"101###1\", 1],[\"#11#10#\", 1],[\"#11#1#0\", 1],[\"#110#0#\", 1],[\"10###11\", 1],[\"11##11#\", 1],[\"1010###\", 1],[\"##1110#\", 1],[\"1###111\", 1],[\"#01001#\", 1],[\"#0##011\", 1],[\"#000101\", 1],[\"##11#01\", 1],[\"#111##1\", 1],[\"###1011\", 1],[\"1##01#1\", 1],[\"1#11##1\", 1],[\"1##011#\", 1],], # [\"1#1##01\", 1], is missing\n", - " \"MM401\": [[\"11####1\", 0],[\"1#1###1\", 0],[\"###1##1\", 0],[\"1#10###\", 0],[\"##1111#\", 0],[\"11#0###\", 0],[\"1#1#11#\", 0],[\"0#0###0\", 1],[\"#0000##\", 1],[\"0####00\", 1],[\"###10#0\", 1],[\"###1#00\", 1],[\"#00#0#0\", 1],[\"##01##0\", 1], [\"1###1#1\", 0],[\"0##0###\", 1], ], # [\"1##01##\", 0],[\"0###0#0\", 1],are missing\n", - "}\n", - "\n", - "automata_output_list = {\n", - " 'GKL' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", - " 'GP' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'GEP_1' : ['0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'GEP_2' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1'],\n", - " 'Davis' : ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '1', '1', '1', '1'],\n", - " 'Das' : ['0', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " 'ABK' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1'],\n", - " # 'DMC' : ['0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '1'],\n", - " # 'COE_1' : ['0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '0', '1', '1', '0', '1', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1'],\n", - " 'COE_2' : ['0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '0', '0', '0', '1', '1', '0', '0', '1', '1', '1', '0', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '1', '0', '1', '1', '1', '0', '0', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1', '0', '0', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '1', '1', '1', '1', '0', '0', '1', '1', '1', '1', '0', '1', '0', '1', '1', '1', '1', '1'],\n", - " 'MM401' : ['1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '0', '0', '1', '1', '1', '1', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '1', '0', '1', '0', '0', '0']\n", - "}\n", - "\n", - "for automata in incomplete_automata:\n", - " node = None\n", - " generated_node_permutations = None\n", - " node = BooleanNode.from_partial_lut(incomplete_automata[automata])\n", - " '''print(f\"Count of '?' {node.outputs.count('?')}\")\n", - " print(f\"Count of '1' {node.outputs.count('1')}\")\n", - " print(f\"Count of '0' {node.outputs.count('0')}\")\n", - " # indices where the output is '?'\n", - " indices = [i for i, x in enumerate(node.outputs) if x == \"?\"]\n", - " print(f\"Indices of '?' {indices}\")'''\n", - "\n", - " generated_node_permutations = BooleanNode.generate_with_required_bias( node, required_node_bias=0.5, verbose=True)\n", - " list_of_output_lists = [node.outputs for node in generated_node_permutations]\n", - "\n", - " # print(automata)\n", - "\n", - " #checking if original rule is contained in the list of generated rules, to verify if the function is working correctly\n", - " if automata_output_list[automata] in list_of_output_lists:\n", - " print(\"Found a match\")\n", - " else:\n", - " print(\"No match found\")\n", - "\n" - ] } ], "metadata": { From 26104c561d88737d65e717f59e8dad3784a7531d Mon Sep 17 00:00:00 2001 From: Srikanth Iyer Date: Thu, 27 Jun 2024 10:21:42 -0400 Subject: [PATCH 14/14] updated generate_with_required_bias : modified sampling randomization --- cana/boolean_node.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/cana/boolean_node.py b/cana/boolean_node.py index 924f72a..7da5f27 100644 --- a/cana/boolean_node.py +++ b/cana/boolean_node.py @@ -984,7 +984,7 @@ def from_partial_lut( # Fill missing output values with the specified bias or with specified effective connectivity or randomly - if fill_missing_output_randomly: # TODO : [SRI] should this also return a list like the others? + if fill_missing_output_randomly: # Replace '?' in generated_node.outputs with 0 or 1 randomly generated_node.outputs = [ random.choice(["0", "1"]) if output == "?" else output @@ -1002,7 +1002,6 @@ def from_partial_lut( def generate_with_required_bias( self, required_node_bias=None, - # limit=1000, verbose=False, *args, **kwargs, @@ -1013,7 +1012,6 @@ def generate_with_required_bias( Args: required_node_bias (float) : The required node bias to fill the missing output values with. - limit (int) : The maximum number of permutations to generate. If the total number of permutations is greater than the limit, then a random subset of the permutations is generated. verbose (bool) : If True, print additional information. Returns: @@ -1083,22 +1081,15 @@ def generate_with_required_bias( combinationsnumber = comb(number_of_missing_values, ones_to_be_generated) - # if combinationsnumber > limit: - # warnings.warn( - # f"Total possible permutaions = {combinationsnumber}. Selecting {limit} permutations randomly." - # ) - # create a list of all possible unique arrangements of the missing output values - # combinations = list(islice(set(permutations(missing_output_values)), limit)) def unique_permutations_missing_values(elements, n): """ Generate n unique permutations of elements. """ seen = set() - # elements = list(elements) # Ensure we can shuffle - # random.shuffle(elements) # Shuffle to ensure randomness in subsets - for perm in permutations(elements): - perm = list(perm) - random.shuffle(perm) # Shuffle to ensure randomness in subsets + + while len(seen) < n: + perm = elements.copy() + random.shuffle(perm) perm_as_str = str(perm) # Convert to string for hashability if perm_as_str not in seen: seen.add(perm_as_str) @@ -1112,6 +1103,10 @@ def unique_permutations_missing_values(elements, n): generated_node_permutations = [] def node_permutations(combinations, node_outputs, *args, **kwargs): + """ + Applying the generated combinations to the missing output values and generating the BooleanNode objects. + """ + for combination in combinations: combination = list(combination) generated_outputs = node_outputs.copy() @@ -1138,7 +1133,7 @@ def node_permutations(combinations, node_outputs, *args, **kwargs): print( f"{combinationsnumber:.2e} possible permutation(s) with a bias of {output_bias_for_print}. This is the closest bias less than or equal to the required bias of {bias}." ) - return generated_node_permutations # returning a list of BooleanNode objects with the required bias. + return generated_node_permutations # returning a generator of BooleanNode objects with the required bias. def generate_with_required_effective_connectivity( self,