{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "A quick tutorial showing the features of BoNesis for the synthesis of Most Permissive Boolean Networks from network architecture and dynamical constraints." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import bonesis\n", "import pandas as pd\n", "from colomoto_jupyter import tabulate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The synthesis uses two inputs:\n", "1. the domain of BNs, which can be a single BN, or specified by an influence graph\n", "2. a table (dictionnary) specifying the (partial) observations of the systems\n", "\n", "## Synthesis from influence graph and dynamical constraints\n", "\n", "### Influence graph\n", "\n", "Let us define an influence graph from a list of pairwise interactions, with a sign." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "influences = [\n", "(\"Pax6\",\"Pax6\",dict(sign=1)),\n", "(\"Pax6\",\"Hes5\",dict(sign=1)),\n", "(\"Pax6\",\"Mash1\",dict(sign=1)),\n", "(\"Hes5\",\"Mash1\",dict(sign=-1)),\n", "(\"Hes5\",\"Scl\",dict(sign=1)),\n", "(\"Hes5\",\"Olig2\",dict(sign=1)),\n", "(\"Hes5\",\"Stat3\",dict(sign=1)),\n", "(\"Mash1\",\"Hes5\",dict(sign=-1)),\n", "(\"Mash1\",\"Zic1\",dict(sign=1)),\n", "(\"Mash1\",\"Brn2\",dict(sign=1)),\n", "(\"Zic1\",\"Tuj1\",dict(sign=1)),\n", "(\"Brn2\",\"Tuj1\",dict(sign=1)),\n", "(\"Scl\",\"Olig2\",dict(sign=-1)),\n", "(\"Scl\",\"Stat3\",dict(sign=1)),\n", "(\"Olig2\",\"Scl\",dict(sign=-1)),\n", "(\"Olig2\",\"Myt1L\",dict(sign=1)),\n", "(\"Olig2\",\"Sox8\",dict(sign=1)),\n", "(\"Olig2\",\"Brn2\",dict(sign=-1)),\n", "(\"Stat3\",\"Aldh1L1\",dict(sign=1)),\n", "(\"Myt1L\",\"Tuj1\",dict(sign=1)),\n", "]" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# computing graph layout...\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Pax6\n", "\n", "Pax6\n", "\n", "\n", "\n", "Pax6->Pax6\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Hes5\n", "\n", "Hes5\n", "\n", "\n", "\n", "Pax6->Hes5\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Mash1\n", "\n", "Mash1\n", "\n", "\n", "\n", "Pax6->Mash1\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Hes5->Mash1\n", "\n", "\n", "-\n", "\n", "\n", "\n", "Scl\n", "\n", "Scl\n", "\n", "\n", "\n", "Hes5->Scl\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Olig2\n", "\n", "Olig2\n", "\n", "\n", "\n", "Hes5->Olig2\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Stat3\n", "\n", "Stat3\n", "\n", "\n", "\n", "Hes5->Stat3\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Mash1->Hes5\n", "\n", "\n", "-\n", "\n", "\n", "\n", "Zic1\n", "\n", "Zic1\n", "\n", "\n", "\n", "Mash1->Zic1\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Brn2\n", "\n", "Brn2\n", "\n", "\n", "\n", "Mash1->Brn2\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Scl->Olig2\n", "\n", "\n", "-\n", "\n", "\n", "\n", "Scl->Stat3\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Olig2->Scl\n", "\n", "\n", "-\n", "\n", "\n", "\n", "Olig2->Brn2\n", "\n", "\n", "-\n", "\n", "\n", "\n", "Myt1L\n", "\n", "Myt1L\n", "\n", "\n", "\n", "Olig2->Myt1L\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Sox8\n", "\n", "Sox8\n", "\n", "\n", "\n", "Olig2->Sox8\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Aldh1L1\n", "\n", "Aldh1L1\n", "\n", "\n", "\n", "Stat3->Aldh1L1\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Tuj1\n", "\n", "Tuj1\n", "\n", "\n", "\n", "Zic1->Tuj1\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Brn2->Tuj1\n", "\n", "\n", "+\n", "\n", "\n", "\n", "Myt1L->Tuj1\n", "\n", "\n", "+\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dom1 = bonesis.InfluenceGraph(influences)\n", "dom1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, `dom1` delimits any BN that uses *at most* the listed influences, with the right sign. Thus, some solutions may use only a subset of this influence graph.\n", "\n", "If you want to enforce BNs using *all* the given influences, use the option `exact=True`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "dom2 = bonesis.InfluenceGraph(influences, exact=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For influence graphs with large in-degrees, it is necessary to specify a bound on the number of clauses in the disjunction normal form (DNF) of the BNs with the `maxclause` argument. See `help(bonesis.InfluenceGraph)` for other options." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Observations\n", "\n", "They are specified by a Python dictionnary associating observation names to observed states of a subset of nodes:" ] }, { "cell_type": "code", "execution_count": 5, "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", "
Pax6Hes5Mash1SclOlig2Stat3Zic1Brn2Tuj1Myt1LSox8Aldh1L1
zero000000000000
init100000000000
tM100000
fT111100
tO101000
fMS100010
tS110000
fA100001
\n", "
" ], "text/plain": [ " Pax6 Hes5 Mash1 Scl Olig2 Stat3 Zic1 Brn2 Tuj1 Myt1L Sox8 Aldh1L1\n", "zero 0 0 0 0 0 0 0 0 0 0 0 0\n", "init 1 0 0 0 0 0 0 0 0 0 0 0\n", "tM 1 0 0 0 0 0\n", "fT 1 1 1 1 0 0\n", "tO 1 0 1 0 0 0\n", "fMS 1 0 0 0 1 0\n", "tS 1 1 0 0 0 0\n", "fA 1 0 0 0 0 1" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data = {\n", " \"zero\": {n: 0 for n in dom1}, # all nodes are 0\n", " \"init\": {n: 1 if n == \"Pax6\" else 0 for n in dom1}, # all nodes are 0 but Pax6\n", " \"tM\": {\"Pax6\": 1, \"Tuj1\": 0, \"Scl\": 0, \"Aldh1L1\": 0, \"Olig2\": 0, \"Sox8\": 0},\n", " \"fT\": {\"Pax6\": 1, \"Tuj1\": 1, \"Brn2\": 1, \"Zic1\": 1, \"Aldh1L1\": 0, \"Sox8\": 0},\n", " \"tO\": {\"Pax6\": 1, \"Tuj1\": 0 ,\"Scl\": 0, \"Aldh1L1\": 0, \"Olig2\": 1, \"Sox8\": 0}, \n", " \"fMS\": {\"Pax6\": 1, \"Tuj1\": 0, \"Zic1\": 0, \"Brn2\": 0, \"Aldh1L1\": 0, \"Sox8\": 1},\n", " \"tS\": {\"Pax6\": 1, \"Tuj1\": 0, \"Scl\": 1, \"Aldh1L1\": 0, \"Olig2\": 0, \"Sox8\": 0},\n", " \"fA\": {\"Pax6\": 1, \"Tuj1\": 0, \"Zic1\": 0, \"Brn2\": 0, \"Aldh1L1\": 1, \"Sox8\": 0},\n", "}\n", "pd.DataFrame.from_dict(data, orient=\"index\").fillna('')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dynamical properties" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "bo = bonesis.BoNesis(dom1, data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `data` dictionnary specifies *observations* that can be used to constraint *configurations* (or states) of the network.\n", "\n", "There are two shortcuts for binding a configuration to an observation:\n", "`~bo.obs(\"A\")` is a unique pre-defined configuration bound to the observation `\"A\"`;\n", "`+bo.obs(\"A\")` returns a *new* configuration bound to `\"A\"`. Thus in the following code:\n", "```python\n", "cfg1 = ~bo.obs(\"A\")\n", "cfg2 = ~bo.obs(\"A\")\n", "cfg3 = +bo.obs(\"A\")\n", "cfg4 = +bo.obs(\"A\")\n", "```\n", "`cfg1` and `cfg2` refers to the *same* configuration; whereas `cfg3` and `cfg4` *may* be different.\n", "\n", "### Attractor constraints\n", "\n", "We detail two kind of attractor constraints: fixed points and trap spaces. Both are specified with the `fixed` predicate, which, depending on the argument will enforce the existence of one of the two kinds of attractor.\n", "\n", "#### Fixed points\n", "\n", "When giving a configuration as argument, `fixed` ensures that the configuration is a fixed point:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "bo.fixed(~bo.obs(\"fA\"))\n", "bo.fixed(~bo.obs(\"fMS\"));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Trap spaces\n", "\n", "A trap space specification is given by an observation, which enforces that all the nodes in the given observations can never change of value (thus any reachable attractor have these nodes fixed):" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "fT_tp = bo.fixed(bo.obs(\"fT\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reachability constraints\n", "\n", "Reachability relates to the presence or absence of trajectory between two configurations.\n", "\n", "#### Existence of trajectory\n", "\n", "They can be specified using the `reach` function, or equivalently the `>=` operator between two configurations. The right-hand side can also be a `fixed` constraint." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "~bo.obs(\"init\") >= ~bo.obs(\"tM\") >= fT_tp\n", "~bo.obs(\"init\") >= ~bo.obs(\"tO\") >= ~bo.obs(\"fMS\")\n", "~bo.obs(\"init\") >= ~bo.obs(\"tS\") >= ~bo.obs(\"fA\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Absence of trajectory\n", "\n", "They can be specified using the `nonreach` function, or equivalently the `/` operator between two configurations. The right-hand side can also be a `fixed` constraint." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "~bo.obs(\"zero\") / fT_tp\n", "~bo.obs(\"zero\") / ~bo.obs(\"fMS\")\n", "~bo.obs(\"zero\") / ~bo.obs(\"fA\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Enumeration of compatible BNs\n", "\n", "Enumerations of solutions are done through iterators. The basic one being the `boolean_networks` which returns `mpbn.MPBooleanNetwork` objects." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grounding...done in 0.0s\n", "Aldh1L1 <- Stat3\n", "Brn2 <- Mash1\n", "Hes5 <- !Mash1&Pax6\n", "Mash1 <- !Hes5&Pax6\n", "Myt1L <- 0\n", "Olig2 <- Hes5&!Scl\n", "Pax6 <- Pax6\n", "Scl <- Hes5&!Olig2\n", "Sox8 <- Olig2\n", "Stat3 <- Hes5&Scl\n", "Tuj1 <- Brn2\n", "Zic1 <- Mash1\n", "\n", "Aldh1L1 <- Stat3\n", "Brn2 <- Mash1\n", "Hes5 <- !Mash1\n", "Mash1 <- !Hes5&Pax6\n", "Myt1L <- 1\n", "Olig2 <- Hes5&!Scl\n", "Pax6 <- Pax6\n", "Scl <- Hes5&!Olig2\n", "Sox8 <- Olig2\n", "Stat3 <- Hes5&Scl\n", "Tuj1 <- Zic1\n", "Zic1 <- Mash1\n", "\n" ] } ], "source": [ "for bn in bo.boolean_networks(limit=2): # limit is optional\n", " print(bn)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Display as a table:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grounding...done in 0.0s\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Aldh1L1Brn2Hes5Mash1Myt1LOlig2Pax6SclSox8Stat3Tuj1Zic1
0Stat3Mash1!Mash1!Hes5&Pax61Hes5&!SclPax6Hes5&!Olig2Olig2SclBrn2&Myt1LMash1
1Stat3Mash1!Mash1!Hes5&Pax60Hes5&!SclPax6Hes5&!Olig2Olig2SclZic1Mash1
2Stat3Mash1!Mash1!Hes51Hes5&!SclPax6Hes5&!Olig2Olig2SclBrn2&Zic1Mash1
3Stat3Mash1!Mash1&Pax6!Hes5&Pax6Olig2Hes5&!SclPax6Hes5&!Olig2Olig2SclBrn2&Zic1Mash1
4Stat3Mash1!Mash1&Pax6!Hes5&Pax6Olig2Hes5&!SclPax6Hes5&!Olig2Olig2Scl(Brn2&Myt1L)|(Brn2&Zic1)Mash1
.......................................
1115Stat3Mash1&!Olig2!Mash1&Pax6!Hes50Hes5&!SclPax6!Olig2Olig2Hes5&SclBrn2|Zic1Mash1
1116Stat3Mash1!Mash1&Pax6!Hes50Hes5&!SclPax6!Olig2Olig2Hes5&SclBrn2&Zic1Mash1
1117Stat3Mash1&!Olig2!Mash1&Pax6!Hes50Hes5&!SclPax6!Olig2Olig2Hes5&SclBrn2&Zic1Mash1
1118Stat3Mash1!Mash1!Hes5&Pax60Hes5&!SclPax6!Olig2Olig2Hes5&SclBrn2|Zic1Mash1
1119Stat3Mash1&!Olig2!Mash1!Hes5&Pax60Hes5&!SclPax6!Olig2Olig2Hes5&SclBrn2|Zic1Mash1
\n", "

1120 rows × 12 columns

\n", "
" ], "text/plain": [ " Aldh1L1 Brn2 Hes5 Mash1 Myt1L Olig2 Pax6 \\\n", "0 Stat3 Mash1 !Mash1 !Hes5&Pax6 1 Hes5&!Scl Pax6 \n", "1 Stat3 Mash1 !Mash1 !Hes5&Pax6 0 Hes5&!Scl Pax6 \n", "2 Stat3 Mash1 !Mash1 !Hes5 1 Hes5&!Scl Pax6 \n", "3 Stat3 Mash1 !Mash1&Pax6 !Hes5&Pax6 Olig2 Hes5&!Scl Pax6 \n", "4 Stat3 Mash1 !Mash1&Pax6 !Hes5&Pax6 Olig2 Hes5&!Scl Pax6 \n", "... ... ... ... ... ... ... ... \n", "1115 Stat3 Mash1&!Olig2 !Mash1&Pax6 !Hes5 0 Hes5&!Scl Pax6 \n", "1116 Stat3 Mash1 !Mash1&Pax6 !Hes5 0 Hes5&!Scl Pax6 \n", "1117 Stat3 Mash1&!Olig2 !Mash1&Pax6 !Hes5 0 Hes5&!Scl Pax6 \n", "1118 Stat3 Mash1 !Mash1 !Hes5&Pax6 0 Hes5&!Scl Pax6 \n", "1119 Stat3 Mash1&!Olig2 !Mash1 !Hes5&Pax6 0 Hes5&!Scl Pax6 \n", "\n", " Scl Sox8 Stat3 Tuj1 Zic1 \n", "0 Hes5&!Olig2 Olig2 Scl Brn2&Myt1L Mash1 \n", "1 Hes5&!Olig2 Olig2 Scl Zic1 Mash1 \n", "2 Hes5&!Olig2 Olig2 Scl Brn2&Zic1 Mash1 \n", "3 Hes5&!Olig2 Olig2 Scl Brn2&Zic1 Mash1 \n", "4 Hes5&!Olig2 Olig2 Scl (Brn2&Myt1L)|(Brn2&Zic1) Mash1 \n", "... ... ... ... ... ... \n", "1115 !Olig2 Olig2 Hes5&Scl Brn2|Zic1 Mash1 \n", "1116 !Olig2 Olig2 Hes5&Scl Brn2&Zic1 Mash1 \n", "1117 !Olig2 Olig2 Hes5&Scl Brn2&Zic1 Mash1 \n", "1118 !Olig2 Olig2 Hes5&Scl Brn2|Zic1 Mash1 \n", "1119 !Olig2 Olig2 Hes5&Scl Brn2|Zic1 Mash1 \n", "\n", "[1120 rows x 12 columns]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "solutions = list(bo.boolean_networks())\n", "pd.DataFrame(solutions)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1120" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(solutions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Resulting objects are `MPBooleanNetwor` from the [`mpbn`](https://mpbn.readthedocs.io/) Python library. One can then compute reachability and attractor properties directly:" ] }, { "cell_type": "code", "execution_count": 14, "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", "
Aldh1L1Brn2Hes5Mash1Myt1LOlig2Pax6SclSox8Stat3Tuj1Zic1
0001011101000
1001011001000
2101010110100
3101010010100
4010110100011
\n", "
" ], "text/plain": [ " Aldh1L1 Brn2 Hes5 Mash1 Myt1L Olig2 Pax6 Scl Sox8 Stat3 Tuj1 \\\n", "0 0 0 1 0 1 1 1 0 1 0 0 \n", "1 0 0 1 0 1 1 0 0 1 0 0 \n", "2 1 0 1 0 1 0 1 1 0 1 0 \n", "3 1 0 1 0 1 0 0 1 0 1 0 \n", "4 0 1 0 1 1 0 1 0 0 0 1 \n", "\n", " Zic1 \n", "0 0 \n", "1 0 \n", "2 0 \n", "3 0 \n", "4 1 " ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(solutions[0].attractors())" ] }, { "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", " \n", " \n", " \n", " \n", " \n", "
Zic1Tuj1Stat3Sox8SclPax6Olig2Myt1LMash1Hes5Brn2Aldh1L1
0110001011010
1000101110100
2001011010101
\n", "
" ], "text/plain": [ " Zic1 Tuj1 Stat3 Sox8 Scl Pax6 Olig2 Myt1L Mash1 Hes5 Brn2 \\\n", "0 1 1 0 0 0 1 0 1 1 0 1 \n", "1 0 0 0 1 0 1 1 1 0 1 0 \n", "2 0 0 1 0 1 1 0 1 0 1 0 \n", "\n", " Aldh1L1 \n", "0 0 \n", "1 0 \n", "2 1 " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(solutions[0].attractors(reachable_from=data[\"init\"]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Universal constraints\n", "\n", "We can also enforce universal constraints on fixed points and reachable fixed points.\n", "\n", "#### Universal fixed points\n", "\n", "The following constraint ensures that any fixed point has to match with at least one of the observation given in argument." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "bo.all_fixpoints({bo.obs(obs) for obs in [\"fA\", \"fMS\", \"fT\", \"zero\"]});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Universal reachable fixed points\n", "\n", "The following constraint ensures that any fixed point *reachable* from the configuration on left-hand side has to match with at least one of the given observation." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "~bo.obs(\"init\") >> \"fixpoints\" ^ {bo.obs(obs) for obs in [\"fA\", \"fMS\", \"fT\"]};" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grounding...done in 0.0s\n" ] }, { "data": { "text/plain": [ "88" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bo.boolean_networks().count()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Project solutions per nodes\n", "\n", "To better understand the composition of the different solutions, one can project the solutions on each node: given a node A, it enumerates all the Boolean functions for A that are used in at least one full solution.\n", "\n", "The projected solutions can be accessed from the following object:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Grounding...done in 0.0s\n" ] } ], "source": [ "projs = bo.local_functions()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `projs` object as `as_dict` method which offers a diret access to all the projected solutions. By default, it will enumerate the Boolean functions for each node. The method \"count\" instead returns the number of solutions per node. There is also a `keys` parameter to specify a subset of nodes for the computation." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'Pax6': 1,\n", " 'Hes5': 1,\n", " 'Mash1': 1,\n", " 'Scl': 1,\n", " 'Olig2': 1,\n", " 'Stat3': 2,\n", " 'Zic1': 1,\n", " 'Brn2': 2,\n", " 'Tuj1': 13,\n", " 'Myt1L': 2,\n", " 'Sox8': 1,\n", " 'Aldh1L1': 1}" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "projs.as_dict(method=\"count\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the projected solutions gives an over-approximation of the full set of solutions: the full set of solutions is, in general, a strict subset of the cartesian product:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "104" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from functools import reduce\n", "reduce(int.__mul__, _.values())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Access to the solutions of a specific node can be done as follows, where `view` is an object similar to the one returned by `bo.boolean_network()` (iterator over solutions)." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Zic1',\n", " 'Myt1L|(Brn2&Zic1)',\n", " 'Zic1|(Brn2&Myt1L)',\n", " '(Brn2&Myt1L)|(Brn2&Zic1)',\n", " 'Myt1L|Zic1',\n", " 'Brn2&Zic1',\n", " '(Brn2&Myt1L)|(Brn2&Zic1)|(Myt1L&Zic1)',\n", " 'Brn2|Myt1L|Zic1',\n", " 'Brn2|(Myt1L&Zic1)',\n", " '(Brn2&Zic1)|(Myt1L&Zic1)',\n", " 'Brn2|Myt1L',\n", " 'Brn2',\n", " 'Brn2|Zic1']" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with projs.view(\"Tuj1\") as view:\n", " functions = [f for f in view]\n", "[str(f) for f in functions]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, `projs` has a `as_dataframe` method for pretty display of the projected solutions using *pandas*." ] }, { "cell_type": "code", "execution_count": 23, "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Pax6Hes5Mash1SclOlig2Stat3Zic1Brn2Tuj1Myt1LSox8Aldh1L1
0Pax6!Mash1&Pax6!Hes5&Pax6Hes5&!Olig2Hes5&!SclSclMash1Mash1&!Olig2(Brn2&Zic1)|(Myt1L&Zic1)0Olig2Stat3
1Hes5&SclMash1Brn2|Myt1LOlig2
2Zic1
3Brn2
4Zic1|(Brn2&Myt1L)
5Brn2|Myt1L|Zic1
6Brn2&Zic1
7Myt1L|Zic1
8(Brn2&Myt1L)|(Brn2&Zic1)
9Myt1L|(Brn2&Zic1)
10Brn2|Zic1
11(Brn2&Myt1L)|(Brn2&Zic1)|(Myt1L&Zic1)
12Brn2|(Myt1L&Zic1)
\n", "
" ], "text/plain": [ " Pax6 Hes5 Mash1 Scl Olig2 Stat3 Zic1 \\\n", "0 Pax6 !Mash1&Pax6 !Hes5&Pax6 Hes5&!Olig2 Hes5&!Scl Scl Mash1 \n", "1 Hes5&Scl \n", "2 \n", "3 \n", "4 \n", "5 \n", "6 \n", "7 \n", "8 \n", "9 \n", "10 \n", "11 \n", "12 \n", "\n", " Brn2 Tuj1 Myt1L Sox8 Aldh1L1 \n", "0 Mash1&!Olig2 (Brn2&Zic1)|(Myt1L&Zic1) 0 Olig2 Stat3 \n", "1 Mash1 Brn2|Myt1L Olig2 \n", "2 Zic1 \n", "3 Brn2 \n", "4 Zic1|(Brn2&Myt1L) \n", "5 Brn2|Myt1L|Zic1 \n", "6 Brn2&Zic1 \n", "7 Myt1L|Zic1 \n", "8 (Brn2&Myt1L)|(Brn2&Zic1) \n", "9 Myt1L|(Brn2&Zic1) \n", "10 Brn2|Zic1 \n", "11 (Brn2&Myt1L)|(Brn2&Zic1)|(Myt1L&Zic1) \n", "12 Brn2|(Myt1L&Zic1) " ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "projs.as_dataframe()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exportation\n", "\n", "A self-contained bash-script for customizing the ASP code and performing the enumeration off-line can be exported as follows." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "view = bo.boolean_networks()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "view.standalone(output_filename=\"tutorial.asp\")" ] }, { "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.8.7" } }, "nbformat": 4, "nbformat_minor": 4 }