9a. Fixed points and composite functions


[1]:
# Colab setup ------------------
import os, sys, subprocess
if "google.colab" in sys.modules:
    cmd = "pip install --upgrade watermark"
    process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
# ------------------------------

import numpy as np

import bokeh.plotting
import bokeh.io

bokeh.io.output_notebook()
Loading BokehJS ...

In this technical appendix, we demonstrate the use of composite functions for simplifying the procedure of finding fixed points for dynamical systems that have certain symmetries. We do this for the protein-only repressilator system. Recalling from Chapter 9, the dimensionless dynamical equations may be written compactly as

\begin{align} \frac{\mathrm{d}x_i}{\mathrm{d}t} &= \frac{\beta}{1 + x_j^n} - x_i, \quad \text{ with } (i,j) \text{ pairs } (1,3), (2,1), (3,2). \end{align}

We find fixed point(s) by solving \(\mathrm{d}x_i/\mathrm{d}t = 0\) for each \(x_i\). This results in three equations,

\begin{align} &x_1 = \frac{\beta}{1+x_3^n}, \\[1em] &x_2 = \frac{\beta}{1+x_1^n}, \\[1em] &x_3 = \frac{\beta}{1+x_2^n}. \end{align}

In the first equation, \(x_1\) is dependent on \(x_3\), which is in turn dependent on \(x_2\) via the third equation. The loop is closed when we see that \(x_2\) is dependent on \(x_1\) via the second equation. To make progress in solving these equations, we can substitute the expression for \(x_3\) into that for \(x_1\) to get

\begin{align} x_1 = \frac{\beta}{1 + \left(\displaystyle{\frac{\beta}{1 + x_2^n}}\right)^n}. \end{align}

We can then substitute the expression for for \(x_2\) to get

\begin{align} x_1 = \frac{\beta}{1 + \displaystyle{\left(\frac{\beta}{1 + \left(\displaystyle{\frac{\beta}{1+x_1^n}}\right)^n}\right)^n}}. \end{align}

This unwieldy expression can be written more conveniently as a composition of functions. Specifically,

\begin{align} x_1 = f(f(f(x_1))) \equiv f\!f\!f(x_1), \end{align}

where \begin{align} f(x) = \frac{\beta}{1+x^n}. \end{align}

By symmetry, this relation holds for repressors 2 and 3 as well, so we have

\begin{align} x_i = f\!f\!f(x_i), \end{align}

for \(i = 1, 2, 3\). Writing the relationship for the fixed point(s) with a composition of functions is useful because we can easily compute the derivatives of the composite function using the chain rule.

\begin{align} (f\!f\,)'(x) &= f'(f(x))\cdot f'(x), \\[1em] (f\!f\!f\,)'(x) &= f'(f\!f(x)) \cdot (f\!f\,)'(x) = f'(f(f(x))) \cdot f'(f(x)) \cdot f'(x). \end{align}

Now, since \(f(x)\) is monotonically decreasing, \(f'(x) < 0\), and also \(f'(f(x)) < 0\). This means that \(f\!f'(x) > 0\), so \(f\!f(x)\) is monotonically increasing. Now, \(f'(f\!f(x)) < 0\), since \(f'(\text{anything monotonically increasing}) < 0\). This means that \(f\!f\!f(x)\) is monotonically decreasing. Since \(x_i\) is increasing, there is a single fixed point with \(x = f\!f\!f(x)\). This is more clear if we look at a plot.

[2]:
# Parameters
beta, n = 3, 2

# f(x)
f = lambda x: beta / (1 + x ** n)

# Make composition of functions
x = np.linspace(0, 3, 200)
fff = f(f(f(x)))

# Show plot
p = bokeh.plotting.figure(
    height=300, width=300, x_axis_label="x", x_range=[0, 3], y_range=[0, 3]
)
p.line(x, x, line_width=2, legend_label="x")
p.line(x, fff, line_width=2, color="orange", legend_label="fff(x)")
p.legend.location = "center_right"

bokeh.io.show(p)

This is very useful, since we showed that there is a single fixed point. Because the time derivative of \(x_1\), \(x_2\) and \(x_3\) all vanish at the fixed point, and we have shown that the fixed point is unique, we have

\begin{align} x_1 = x_2 = x_3 \equiv x_0 = \frac{\beta}{1 + x_0^n}, \end{align}

or

\begin{align} \beta = x_0(1+x_0^n). \end{align}

For this example, we see that when we can express a system of algebraic equations as a relationship between composite functions, we can readily use properties of the derivatives of composite functions to obtain insights about the solutions of the original algebraic system.

Computing environment

[3]:
%load_ext watermark
%watermark -v -p numpy,bokeh,jupyterlab
Python implementation: CPython
Python version       : 3.10.10
IPython version      : 8.12.0

numpy     : 1.23.5
bokeh     : 3.1.0
jupyterlab: 3.5.3