{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 9c. Numerical one-dimensional bounded root finding\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": [], "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", "import scipy.optimize" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When finding the fixed point of the repressilator system that includes mRNA in [Chapter 9](../chapters/09_repressilator.ipynb), we were tasked with finding the value of $x_0$ that is the solution to\n", "\n", "\\begin{align}\n", "(x_0 - \\beta\\rho)(1+x_0^n) = \\beta.\n", "\\end{align}\n", "\n", "Finding an analytical solution of this equation for $x_0$ is usually impossible. (It is possible when $n$ is an integer between zero and three.) We therefore seek a numerical method for finding $x_0$. This is an example of a **root finding problem**. It can be cast into a problem of finding $f(x) = 0$ for some function $f(x)$. Do not confuse this $f(x)$ with regulatory functions we have used; we are using $f(x)$ here to be an arbitrary function. In the present case, $f(x) = \\beta - (x_0 - \\beta\\rho)(1+x_0^n)$.\n", "\n", "We will explore algorithms for more general multidimensional root finding problem in later chapters, but for now, we seek a scalar $x_0$. In this case, we know a lot about the fixed point. We know from our analysis in [Chapter 9](../chapters/09_repressilator.ipynb) that it exists and is unique. We also know that it lies between $x_0 = 0$ (where $f(0) = \\beta(1+\\rho) > 0$) and $x_0 = \\beta(1+\\rho)$ (since $f(\\beta(1+\\rho)) < 0$). When we have bounds and guarantees of uniqueness for a scalar root, we can use a [bisection method](https://en.wikipedia.org/wiki/Bisection_method) to find the root. The bisection method is guaranteed to find the root of the function $f(x)$ on an interval $[a,b]$, provided $f(x)$ is continuous and $f(a)$ and $f(b)$ have opposite sign, which is the case here. \n", "\n", "[Brent's method](https://en.wikipedia.org/wiki/Brent%27s_method) also has this guarantee, but is more efficient that using bisection. We will not go into the details of these respective algorithms, and leave you to read the Wikipedia pages we have linked to, which provide quite clear descriptions.\n", "\n", "Brent's method is available in the `scipy.optimize.brentq()` function. It takes as an argument the function $f(x)$ whose root is to be found, and the left and right bounds for the root. We can write a function to find the fixed point for given $\\beta$, $\\rho$, and $n$." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2019-06-05T00:52:06.289966Z", "start_time": "2019-06-05T00:52:06.285757Z" } }, "outputs": [], "source": [ "def fixed_point(beta, n, rho):\n", " def _root_function(x):\n", " return beta - (x - beta * rho) * (1 + x ** n)\n", "\n", " return scipy.optimize.brentq(_root_function, 0, beta * (1 + rho))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As an example, we can put it to use for values of $\\beta$, $n$, and $\\rho$ for which an analytical solution is not possible." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.4507547941440446" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "beta = 10.07\n", "n = 4.78\n", "rho = 0.34\n", "\n", "fixed_point(beta, n, rho)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Computing environment" ] }, { "cell_type": "code", "execution_count": 4, "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", "scipy : 1.10.1\n", "jupyterlab: 3.5.3\n", "\n" ] } ], "source": [ "%load_ext watermark\n", "%watermark -v -p numpy,scipy,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 }