{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 9b. Linear stability analysis\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2019-06-05T00:52:06.213619Z", "start_time": "2019-06-05T00:52:06.190940Z" }, "tags": [ "hide-input" ] }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " Loading BokehJS ...\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " const force = true;\n", "\n", " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", " root._bokeh_onload_callbacks = [];\n", " root._bokeh_is_loading = undefined;\n", " }\n", "\n", "const JS_MIME_TYPE = 'application/javascript';\n", " const HTML_MIME_TYPE = 'text/html';\n", " const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n", " const CLASS_NAME = 'output_bokeh rendered_html';\n", "\n", " /**\n", " * Render data to the DOM node\n", " */\n", " function render(props, node) {\n", " const script = document.createElement(\"script\");\n", " node.appendChild(script);\n", " }\n", "\n", " /**\n", " * Handle when an output is cleared or removed\n", " */\n", " function handleClearOutput(event, handle) {\n", " const cell = handle.cell;\n", "\n", " const id = cell.output_area._bokeh_element_id;\n", " const server_id = cell.output_area._bokeh_server_id;\n", " // Clean up Bokeh references\n", " if (id != null && id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", "\n", " if (server_id !== undefined) {\n", " // Clean up Bokeh references\n", " const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n", " cell.notebook.kernel.execute(cmd_clean, {\n", " iopub: {\n", " output: function(msg) {\n", " const id = msg.content.text.trim();\n", " if (id in Bokeh.index) {\n", " Bokeh.index[id].model.document.clear();\n", " delete Bokeh.index[id];\n", " }\n", " }\n", " }\n", " });\n", " // Destroy server and session\n", " const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n", " cell.notebook.kernel.execute(cmd_destroy);\n", " }\n", " }\n", "\n", " /**\n", " * Handle when a new output is added\n", " */\n", " function handleAddOutput(event, handle) {\n", " const output_area = handle.output_area;\n", " const output = handle.output;\n", "\n", " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n", " if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n", " return\n", " }\n", "\n", " const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", "\n", " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n", " toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n", " // store reference to embed id on output_area\n", " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", " }\n", " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", " const bk_div = document.createElement(\"div\");\n", " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", " const script_attrs = bk_div.children[0].attributes;\n", " for (let i = 0; i < script_attrs.length; i++) {\n", " toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n", " toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n", " }\n", " // store reference to server id on output_area\n", " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", " }\n", " }\n", "\n", " function register_renderer(events, OutputArea) {\n", "\n", " function append_mime(data, metadata, element) {\n", " // create a DOM node to render to\n", " const toinsert = this.create_output_subarea(\n", " metadata,\n", " CLASS_NAME,\n", " EXEC_MIME_TYPE\n", " );\n", " this.keyboard_manager.register_events(toinsert);\n", " // Render to node\n", " const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", " render(props, toinsert[toinsert.length - 1]);\n", " element.append(toinsert);\n", " return toinsert\n", " }\n", "\n", " /* Handle when an output is cleared or removed */\n", " events.on('clear_output.CodeCell', handleClearOutput);\n", " events.on('delete.Cell', handleClearOutput);\n", "\n", " /* Handle when a new output is added */\n", " events.on('output_added.OutputArea', handleAddOutput);\n", "\n", " /**\n", " * Register the mime type and append_mime function with output_area\n", " */\n", " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", " /* Is output safe? */\n", " safe: true,\n", " /* Index of renderer in `output_area.display_order` */\n", " index: 0\n", " });\n", " }\n", "\n", " // register the mime type if in Jupyter Notebook environment and previously unregistered\n", " if (root.Jupyter !== undefined) {\n", " const events = require('base/js/events');\n", " const OutputArea = require('notebook/js/outputarea').OutputArea;\n", "\n", " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", " register_renderer(events, OutputArea);\n", " }\n", " }\n", " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", " root._bokeh_timeout = Date.now() + 5000;\n", " root._bokeh_failed_load = false;\n", " }\n", "\n", " const NB_LOAD_WARNING = {'data': {'text/html':\n", " \"
\\n\"+\n", " \"

\\n\"+\n", " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", " \"

\\n\"+\n", " \"\\n\"+\n", " \"\\n\"+\n", " \"from bokeh.resources import INLINE\\n\"+\n", " \"output_notebook(resources=INLINE)\\n\"+\n", " \"\\n\"+\n", " \"
\"}};\n", "\n", " function display_loaded() {\n", " const el = document.getElementById(\"p1001\");\n", " if (el != null) {\n", " el.textContent = \"BokehJS is loading...\";\n", " }\n", " if (root.Bokeh !== undefined) {\n", " if (el != null) {\n", " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n", " }\n", " } else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(display_loaded, 100)\n", " }\n", " }\n", "\n", " function run_callbacks() {\n", " try {\n", " root._bokeh_onload_callbacks.forEach(function(callback) {\n", " if (callback != null)\n", " callback();\n", " });\n", " } finally {\n", " delete root._bokeh_onload_callbacks\n", " }\n", " console.debug(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(css_urls, js_urls, callback) {\n", " if (css_urls == null) css_urls = [];\n", " if (js_urls == null) js_urls = [];\n", "\n", " root._bokeh_onload_callbacks.push(callback);\n", " if (root._bokeh_is_loading > 0) {\n", " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls == null || js_urls.length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " root._bokeh_is_loading = css_urls.length + js_urls.length;\n", "\n", " function on_load() {\n", " root._bokeh_is_loading--;\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", " run_callbacks()\n", " }\n", " }\n", "\n", " function on_error(url) {\n", " console.error(\"failed to load \" + url);\n", " }\n", "\n", " for (let i = 0; i < css_urls.length; i++) {\n", " const url = css_urls[i];\n", " const element = document.createElement(\"link\");\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.rel = \"stylesheet\";\n", " element.type = \"text/css\";\n", " element.href = url;\n", " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", " document.body.appendChild(element);\n", " }\n", "\n", " for (let i = 0; i < js_urls.length; i++) {\n", " const url = js_urls[i];\n", " const element = document.createElement('script');\n", " element.onload = on_load;\n", " element.onerror = on_error.bind(null, url);\n", " element.async = false;\n", " element.src = url;\n", " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.head.appendChild(element);\n", " }\n", " };\n", "\n", " function inject_raw_css(css) {\n", " const element = document.createElement(\"style\");\n", " element.appendChild(document.createTextNode(css));\n", " document.body.appendChild(element);\n", " }\n", "\n", " const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.0.min.js\"];\n", " const css_urls = [];\n", "\n", " const inline_js = [ function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", "function(Bokeh) {\n", " }\n", " ];\n", "\n", " function run_inline_js() {\n", " if (root.Bokeh !== undefined || force === true) {\n", " for (let i = 0; i < inline_js.length; i++) {\n", " inline_js[i].call(root, root.Bokeh);\n", " }\n", "if (force === true) {\n", " display_loaded();\n", " }} else if (Date.now() < root._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!root._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " root._bokeh_failed_load = true;\n", " } else if (force !== true) {\n", " const cell = $(document.getElementById(\"p1001\")).parents('.cell').data().cell;\n", " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", " }\n", " }\n", "\n", " if (root._bokeh_is_loading === 0) {\n", " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", " run_inline_js();\n", " } else {\n", " load_libs(css_urls, js_urls, function() {\n", " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", "}(window));" ], "application/vnd.bokehjs_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n const el = document.getElementById(\"p1001\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.0.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\nif (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"p1001\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Colab setup ------------------\n", "import os, sys, subprocess\n", "if \"google.colab\" in sys.modules:\n", " cmd = \"pip install --upgrade watermark\"\n", " process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", " stdout, stderr = process.communicate()\n", "# ------------------------------\n", "\n", "import numpy as np\n", "\n", "import bokeh.plotting\n", "import bokeh.io\n", "\n", "bokeh.io.output_notebook()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Thus far, we have assessed the stability of fixed points of a dynamical system graphically. We have drawn plots of production rates and degradation rates of gene products, with the crossing of these respective plots being fixed points. We then investigated when degradation was faster than production, and vice versa, to determine whether a system is attracted toward or repelled away from a fixed point. We also did similar nullcline-based analysis.\n", "\n", "In this technical appendix, we present a more general, and very useful, approach called **linear stability analysis**. We first give a minimal introduction to the technique, and then apply it to the repressilator. You can read about the technique in greater depth in [Strogatz's book](https://doi.org/10.1201/9780429492563)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A minimal introduction to linear stability analysis\n", "\n", "The main idea behind linear stability analysis is to locally approximate a *nonlinear* dynamical system by its Taylor series to first order near the fixed point, and then examine the behavior of the resulting simpler linear system. The **Hartman-Grobman theorem** (which we will not derive here) ensures that the linearized system faithfully represents the phase portrait of the full nonlinear system near the fixed point.\n", "\n", "Say we have a dynamical system with variables $\\mathbf{u}$ with\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\mathbf{u}}{\\mathrm{d}t} = \\mathbf{f}(\\mathbf{u}),\n", "\\end{align}\n", "\n", "where $\\mathbf{f}(\\mathbf{u})$ is a vector-valued function, i.e.,\n", "\n", "\\begin{align}\n", "\\mathbf{f}(\\mathbf{u}) = (f_1(u_1, u_2, \\ldots), f_2(u_1, u_2, \\ldots), \\ldots).\n", "\\end{align}\n", "\n", "Assuming there is a fixed point $\\mathbf{u}_0$, linear stability analysis proceeds with the following steps:\n", "\n", "**1.** Linearize about $\\mathbf{u}_0$, defining $\\delta\\mathbf{u} = \\mathbf{u} - \\mathbf{u}_0$. To do this, expand $f(\\mathbf{u})$ in a Taylor series about $\\mathbf{u}_0$ to first order.\n", " \n", "\\begin{align}\n", "\\mathbf{f}(\\mathbf{u}) = \\mathbf{f}(\\mathbf{u}_0) + \\nabla \\mathbf{f}(\\mathbf{u}_0)\\cdot \\delta\\mathbf{u} + \\cdots,\n", "\\end{align}\n", "\n", "where $\\nabla \\mathbf{f}(\\mathbf{u}_0) \\equiv \\mathsf{A}$ is the Jacobi matrix evaluated at $\\mathbf{u}_0$,\n", "\n", "\\begin{align}\n", "\\nabla \\mathbf{f}(\\mathbf{u}_0) \\equiv \\mathsf{A} = \\left.\\begin{pmatrix}\n", "\\frac{\\partial f_1}{\\partial u_1} & \\frac{\\partial f_1}{\\partial u_2} & \\cdots \\\\[0.5em]\n", "\\frac{\\partial f_2}{\\partial u_1} & \\frac{\\partial f_2}{\\partial u_2} & \\cdots \\\\\n", "\\vdots & \\vdots & \\ddots\n", "\\end{pmatrix}\\right|_{\\mathbf{\\, u}_0}\n", "\\end{align}\n", "\n", "Thus, we have\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\mathbf{u}}{\\mathrm{d}t} = \\frac{\\mathrm{d}\\mathbf{u}_0}{\\mathrm{d}t} + \\frac{\\mathrm{d}\\delta\\mathbf{u}}{\\mathrm{d}t}\n", "= \\mathbf{f}(\\mathbf{u}_0) + \\mathsf{A} \\cdot \\delta\\mathbf{u} + \\text{higher order terms}.\n", "\\end{align}\n", "\n", "Since\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\mathbf{u}_0}{\\mathrm{d}t} = \\mathbf{f}(\\mathbf{u}_0) = 0,\n", "\\end{align}\n", "\n", "we have, to linear order,\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\delta\\mathbf{u}}{\\mathrm{d}t} = \\mathsf{A} \\cdot \\delta\\mathbf{u}.\n", "\\end{align}\n", "\n", "This is now a system of _linear_ ordinary differential equations. If this were a one-dimensional system, the solution would be an exponential $\\delta u \\propto \\mathrm{e}^{\\lambda u}$. In the multidimensional case, the growth rate $\\lambda$ is replaced by a set of eigenvalues of $\\mathsf{A}$ that represent the growth rates in different directions, given by the eigenvectors of $\\mathsf{A}$\n", " \n", "**2.** Compute the eigenvalues, $\\lambda$ of $\\mathsf{A}$.\n", "\n", "**3.** Determine the stability of the fixed point using the following rules.\n", "\n", "- If $\\mathrm{Re}(\\lambda) < 0$ for all $\\lambda$, then the fixed point $\\mathbf{u}_0$ is linearly stable.\n", "- If $\\mathrm{Re}(\\lambda) > 0$ for any $\\lambda$, then the fixed point $\\mathbf{u}_0$ is linearly unstable. \n", "- If $\\mathrm{Im}(\\lambda) \\ne 0$ for a linearly unstable fixed point, the trajectories spiral out, potentially leading to oscillatory dynamics.\n", "- If $\\mathrm{Re}(\\lambda) = 0$ for one or more $\\lambda$, with the rest having $\\mathrm{Re}(\\lambda) < 0$, then the fixed point $\\mathbf{u}_0$ lies at a bifurcation.\n", "\n", "So, if we can assess the dynamics of the linearized system near the fixed point, we can get an idea what is happening with the full system." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Handy Taylor series of Hill functions\n", "\n", "Because we model dynamics using Hill function so often, we will write the linearization of them here for you to memorize.\n", "\n", "\\begin{align}\n", "\\frac{x^n}{1+x^n} &= \\frac{x_0^n}{1+x_0^n} + \\frac{n x_0^{n-1}}{(1+x_0^n)^2}\\,\\delta x + \\text{higher order terms}, \\\\[1em]\n", "\\frac{1}{1+x^n} &= \\frac{1}{1+x_0^n} - \\frac{n x_0^{n-1}}{(1+x_0^n)^2}\\,\\delta x + \\text{higher order terms}.\n", "\\end{align}\n", "\n", "In the following analysis of the repressilator, we only need the second, repressing case." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Linear stability analysis for the repressilator\n", "\n", "In [Technical Appendix 9a](09a_composite_functions_to_find_fixed_point.ipynb), we wrote the dimensionless dynamical equations of the repressilator as\n", "\n", "\\begin{align}\n", "&\\frac{\\mathrm{d}x_1}{\\mathrm{d}t} = \\frac{\\beta}{1 + x_3^n} - x_1, \\\\[1em]\n", "&\\frac{\\mathrm{d}x_2}{\\mathrm{d}t} = \\frac{\\beta}{1 + x_1^n} - x_2, \\\\[1em]\n", "&\\frac{\\mathrm{d}x_3}{\\mathrm{d}t} = \\frac{\\beta}{1 + x_2^n} - x_3,\n", "\\end{align}\n", "\n", "and showed that there exists a unique fixed point that satisfies\n", "\n", "\\begin{align}\n", "x_1 = x_2 = x_3 \\equiv x_0 = \\frac{\\beta}{1 + x_0^n},\n", "\\end{align}\n", "\n", "or\n", "\n", "\\begin{align}\n", "\\beta = x_0(1+x_0^n).\n", "\\end{align}\n", "\n", "To perform linear stability analysis for the repressilator, we begin by writing the linearized system, performing a Taylor series expansion about the fixed point $x_1 = x_2 = x_3 \\equiv x_0$.\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}\\delta x_1}{\\mathrm{d}t} &\\approx -\\frac{\\beta n x_0^{n-1}}{(1+x_0^n)^2}\\,\\delta x_3 - \\delta x_1, \\\\[1em]\n", "\\frac{\\mathrm{d}\\delta x_2}{\\mathrm{d}t} &\\approx -\\frac{\\beta n x_0^{n-1}}{(1+x_0^n)^2}\\,\\delta x_1 - \\delta x_2, \\\\[1em]\n", "\\frac{\\mathrm{d}\\delta x_3}{\\mathrm{d}t} &\\approx -\\frac{\\beta n x_0^{n-1}}{(1+x_0^n)^2}\\,\\delta x_2 - \\delta x_3.\n", "\\end{align}\n", "\n", "Defining\n", "\n", "\\begin{align}\n", "a = \\frac{\\beta n x_0^{n-1}}{(1+x_0^n)^2},\n", "\\end{align}\n", "\n", "we can write this in matrix form as\n", "\n", "\\begin{align}\n", "\\frac{\\mathrm{d}}{\\mathrm{d}t}\\begin{pmatrix}\n", "\\delta x_1 \\\\\n", "\\delta x_2 \\\\\n", "\\delta x_3\n", "\\end{pmatrix}\n", "= \\mathsf{A}\\cdot\\begin{pmatrix}\n", "\\delta x_1 \\\\\n", "\\delta x_2 \\\\\n", "\\delta x_3\n", "\\end{pmatrix},\n", "\\end{align}\n", "\n", "with\n", "\n", "\\begin{align}\n", "\\mathsf{A} = -\\begin{pmatrix}\n", "1 & 0 & a \\\\\n", "a & 1 & 0 \\\\\n", "0 & a & 1\n", "\\end{pmatrix}.\n", "\\end{align}\n", "\n", "To compute the eigenvalues of $\\mathsf{A}$, we compute the characteristic polynomial using cofactors,\n", "\n", "\\begin{align}\n", "(1+\\lambda)(1+\\lambda)^2 + a(a^2) = (1+\\lambda)^3 + a^3 = 0.\n", "\\end{align}\n", "\n", "This is solved to give\n", "\n", "\\begin{align}\n", "\\lambda = -1 + a \\sqrt[3]{-1}.\n", "\\end{align}\n", "\n", "Recalling that there are three cube roots of $-1$, we get our three eigenvalues.\n", "\n", "\\begin{align}\n", "&\\lambda = -1 - a, \\\\[1em]\n", "&\\lambda = -1 + \\frac{a}{2}(1 + i\\sqrt{3}),\\\\[1em]\n", "&\\lambda = -1 + \\frac{a}{2}(1 - i\\sqrt{3}).\n", "\\end{align}\n", "\n", "The first eigenvalue is always real and negative. The second two have a positive real part if $a > 2$;\n", "\n", "\\begin{align}\n", "a = \\frac{\\beta n x_0^{n-1}}{(1 + x_0^n)^2} > 2.\n", "\\end{align}\n", "\n", "We previously derived that the fixed point $x_0$ satisfies\n", "\n", "\\begin{align}\n", "\\beta = x_0(1+x_0^n),\n", "\\end{align}\n", "\n", "so\n", "\n", "\\begin{align}\n", "a = \\frac{\\beta n x_0^{n-1}}{(1 + x_0^n)^2} = \\frac{n x_0^n}{1 + x_0^n}.\n", "\\end{align}\n", "\n", "So, $a>2$ only if $n > 2$, meaning that we _must_ have ultrasensitivity for the fixed point to be unstable.\n", "\n", "At the bifurcation,\n", "\n", "\\begin{align}\n", "a = \\frac{n x_0^n}{1+x_0^n} = 2,\n", "\\end{align}\n", "\n", "so\n", "\n", "\\begin{align}\n", "x_0^n = \\frac{2}{n-2}.\n", "\\end{align}\n", "\n", "Again using $\\beta = x_0(1+x_0^n)$, we can write\n", "\n", "\\begin{align}\n", "\\beta = \\frac{n}{2}\\left(\\frac{n}{2} - 1\\right)^{-\\frac{n+1}{n}}\n", "\\end{align}\n", "\n", "at the bifurcation. So, for $n > 2$ and\n", "\n", "\\begin{align}\n", "\\beta > \\frac{n}{2}\\left(\\frac{n}{2} - 1\\right)^{-\\frac{n+1}{n}},\n", "\\end{align}\n", "\n", "we have imaginary eigenvalues with positive real parts. This is therefore an **oscillatory instability**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Linear stability diagram\n", "\n", "When analyzing stability of dynamical systems, it is useful to make a **linear stability diagram**, which is a map of parameter space highlighting stable and unstable regions. We know the bifurcation line is\n", "\n", "\\begin{align}\n", "\\beta = \\frac{n}{2}\\left(\\frac{n}{2} - 1\\right)^{-\\frac{n+1}{n}}.\n", "\\end{align}\n", "\n", "We can plot this line and delineate the regions of stability and instability." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2019-06-05T00:52:06.901929Z", "start_time": "2019-06-05T00:52:06.827613Z" }, "tags": [ "hide-input" ] }, "outputs": [ { "data": { "text/html": [ "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "(function(root) {\n", " function embed_document(root) {\n", " const docs_json = {\"c550b5d9-86e4-4426-b54f-06d62fa44a5f\":{\"version\":\"3.1.0\",\"title\":\"Bokeh Application\",\"defs\":[],\"roots\":[{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1002\",\"attributes\":{\"width\":400,\"height\":300,\"x_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1011\",\"attributes\":{\"start\":2,\"end\":5}},\"y_range\":{\"type\":\"object\",\"name\":\"Range1d\",\"id\":\"p1013\",\"attributes\":{\"start\":1,\"end\":2000}},\"x_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1015\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LogScale\",\"id\":\"p1017\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1010\"},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1054\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1048\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1049\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1050\"},\"data\":{\"type\":\"map\",\"entries\":[[\"x\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[201],\"dtype\":\"float64\",\"order\":\"little\"}],[\"y\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[201],\"dtype\":\"float64\",\"order\":\"little\"}]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1055\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1056\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Patch\",\"id\":\"p1051\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_color\":\"lightgray\",\"line_alpha\":0.7,\"fill_color\":\"lightgray\",\"fill_alpha\":0.7,\"hatch_color\":\"lightgray\",\"hatch_alpha\":0.7}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Patch\",\"id\":\"p1052\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_color\":\"lightgray\",\"line_alpha\":0.1,\"fill_color\":\"lightgray\",\"fill_alpha\":0.1,\"hatch_color\":\"lightgray\",\"hatch_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Patch\",\"id\":\"p1053\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_color\":\"lightgray\",\"line_alpha\":0.2,\"fill_color\":\"lightgray\",\"fill_alpha\":0.2,\"hatch_color\":\"lightgray\",\"hatch_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1063\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1057\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1058\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1059\"},\"data\":{\"type\":\"map\",\"entries\":[[\"x\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[200],\"dtype\":\"float64\",\"order\":\"little\"}],[\"y\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"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\"},\"shape\":[200],\"dtype\":\"float64\",\"order\":\"little\"}]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1064\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1065\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1060\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_width\":4}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1061\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_alpha\":0.1,\"line_width\":4}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1062\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"x\"},\"y\":{\"type\":\"field\",\"field\":\"y\"},\"line_alpha\":0.2,\"line_width\":4}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1072\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1066\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1067\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1068\"},\"data\":{\"type\":\"map\",\"entries\":[[\"text\",[\"stable\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1073\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1074\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1069\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.1},\"y\":{\"type\":\"value\",\"value\":2},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1070\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.1},\"y\":{\"type\":\"value\",\"value\":2},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"},\"text_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1071\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.1},\"y\":{\"type\":\"value\",\"value\":2},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"},\"text_alpha\":{\"type\":\"value\",\"value\":0.2}}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1081\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1075\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1076\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1077\"},\"data\":{\"type\":\"map\",\"entries\":[[\"text\",[\"unstable (limit cycle oscillations)\"]]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1082\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1083\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1078\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.5},\"y\":{\"type\":\"value\",\"value\":100},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1079\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.5},\"y\":{\"type\":\"value\",\"value\":100},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"},\"text_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Text\",\"id\":\"p1080\",\"attributes\":{\"x\":{\"type\":\"value\",\"value\":2.5},\"y\":{\"type\":\"value\",\"value\":100},\"text\":{\"type\":\"field\",\"field\":\"text\"},\"text_color\":{\"type\":\"value\",\"value\":\"black\"},\"text_alpha\":{\"type\":\"value\",\"value\":0.2}}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1005\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1033\"},{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1034\"},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1035\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1036\",\"attributes\":{\"syncable\":false,\"level\":\"overlay\",\"visible\":false,\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"bottom_units\":\"canvas\",\"top_units\":\"canvas\",\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5}}}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1037\"},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1038\"},{\"type\":\"object\",\"name\":\"HelpTool\",\"id\":\"p1039\"}]}},\"left\":[{\"type\":\"object\",\"name\":\"LogAxis\",\"id\":\"p1026\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"LogTicker\",\"id\":\"p1028\",\"attributes\":{\"num_minor_ticks\":10,\"mantissas\":[1,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"LogTickFormatter\",\"id\":\"p1027\"},\"axis_label\":\"\\u03b2\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1029\"}}}],\"below\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1019\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1021\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1020\"},\"axis_label\":\"n\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1022\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1025\",\"attributes\":{\"axis\":{\"id\":\"p1019\"}}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1032\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1026\"}}}]}}],\"callbacks\":{\"type\":\"map\"}}};\n", " const render_items = [{\"docid\":\"c550b5d9-86e4-4426-b54f-06d62fa44a5f\",\"roots\":{\"p1002\":\"fe417eb3-4e8a-4cdd-9758-12be0c1eb66b\"},\"root_ids\":[\"p1002\"]}];\n", " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", " }\n", " if (root.Bokeh !== undefined) {\n", " embed_document(root);\n", " } else {\n", " let attempts = 0;\n", " const timer = setInterval(function(root) {\n", " if (root.Bokeh !== undefined) {\n", " clearInterval(timer);\n", " embed_document(root);\n", " } else {\n", " attempts++;\n", " if (attempts > 100) {\n", " clearInterval(timer);\n", " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n", " }\n", " }\n", " }, 10, root)\n", " }\n", "})(window);" ], "application/vnd.bokehjs_exec.v0+json": "" }, "metadata": { "application/vnd.bokehjs_exec.v0+json": { "id": "p1002" } }, "output_type": "display_data" } ], "source": [ "# Get bifurcation line\n", "n = np.linspace(2.01, 5, 200)\n", "beta = n / 2 * (n / 2 - 1) ** (-(1 + 1 / n))\n", "\n", "# Build the plot\n", "p = bokeh.plotting.figure(\n", " height=300,\n", " width=400,\n", " x_axis_label=\"n\",\n", " y_axis_label=\"β\",\n", " y_axis_type=\"log\",\n", " x_range=[2, 5],\n", " y_range=[1, 2000],\n", ")\n", "p.patch(\n", " np.append(n, n[-1]), np.append(beta, beta[0]), color=\"lightgray\", alpha=0.7\n", ")\n", "p.line(n, beta, line_width=4, color=\"black\")\n", "p.text(x=2.1, y=2, text=[\"stable\"])\n", "p.text(x=2.5, y=100, text=[\"unstable (limit cycle oscillations)\"])\n", "\n", "bokeh.io.show(p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## References\n", "\n", "- Strogatz, S. H., _Nonlinear Dynamics and Chaos With Applications to Physics, Biology, Chemistry, and Engineering, 2nd Ed._, CRC Press, 2015. ([link](https://doi.org/10.1201/9780429492563))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computing environment" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2019-06-05T00:52:08.101915Z", "start_time": "2019-06-05T00:52:08.094114Z" }, "tags": [ "hide-input" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python implementation: CPython\n", "Python version : 3.10.10\n", "IPython version : 8.12.0\n", "\n", "numpy : 1.23.5\n", "bokeh : 3.1.0\n", "jupyterlab: 3.5.3\n", "\n" ] } ], "source": [ "%load_ext watermark\n", "%watermark -v -p numpy,bokeh,jupyterlab" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }