Transcritical bifurcation

We now shift our attention to transcritical bifurcations. In this kind of bifurcation, there is change of stability characteristics of the equilibrium points, i.e. the stable branch becomes unstable and vice-versa as the parameter of the problem is changed.

In [1]:
import numpy as np;
import matplotlib.pyplot as plt;
plt.rcParams.update({"text.usetex":True});
%config InlineBackend.figure_format = "svg"
from ipywidgets import interactive
from scipy.optimize import fsolve
In [2]:
def show_transcrit(r):
    x = np.linspace(-2,2);
    plt.plot(x, r*x-x**2);
    plt.axhline(0, color='k');
    plt.axvline(0, color='m');

w = interactive(show_transcrit, r= (-1, 1, 0.1));
w

In the above interactive widget, we have plotted the function $rx-x^2$, where $r$ can be changed interactively. This shows the presence of two roots (except when $r = 0$) and the slope at the fixed root seems to change as $r$ crosses the origin. This behaviour of the function is at the heart of the transcritical bifurcation.

In [3]:
def f(x, r):
    return r*x- x**2;

def dfdx(x, r):
    return r-2*x;

x = np.linspace(-2, 2); r_a = np.linspace(-2, 2);

for r in r_a:
    sol = fsolve(f, [-2, 2], args=(r), full_output=True)
    if sol[2] == 1: # Solution has convered
        for i in np.arange(0, np.size(sol[0])):
            root = sol[0][i];
            slope_at_root = dfdx(root, r)
            if slope_at_root > 0:
                plt.plot(r, root, 'bx')
            else:
                plt.plot(r, root, 'ro')
ax = plt.gca(); ax.set_aspect(1);
plt.xlim(np.min(r_a), np.max(r_a))
plt.axhline(0); plt.axvline(0)
plt.xlabel("r");
plt.ylabel("x*");
plt.title("Transcritical bifurcation");

The above plot depicts the fixed points and also their stability as the parameter $r$ is varied.

Let's now consider another equation $$\dot{x} = x(1-x^2) - a(1-\exp(-bx))$$. This equation, as can be shown with a bit of manipulation, also has the same normal form as the equation which we discussed above.

In [4]:
def showfun(r):
    a = 1;
    x = np.linspace(-3, 3);
    f = x*(1-x**2) - a*(1-np.exp(-r*x));
    plt.plot(x, f);
    plt.axhline(0, color='k');
    plt.ylim(-1, 1);
    
w = interactive(showfun, r = (-2, 2, 0.1));
w

We can now plot the bifurcation diagram for this equation as shown below:

In [5]:
def f(x, r):
    return x*(1-x**2) - (1-np.exp(-r*x));

def dfdx(x, r):
    return 1-3*x**2 -r*np.exp(-r*x);

x = np.linspace(-2, 2); 
r_a = np.linspace(-2, 2);

for r in r_a:
    sol = fsolve(f, [-2,1, 0,-1, 2], args=(r), full_output=True)
    if sol[2] == 1: # Solution has convered
        for i in np.arange(0, np.size(sol[0])):
            root = sol[0][i];
            slope_at_root = dfdx(root, r)
            if slope_at_root > 0:
                plt.plot(r, root, 'bx')
            else:
                plt.plot(r, root, 'ro')
ax = plt.gca(); ax.set_aspect(1);
plt.xlim(np.min(r_a), np.max(r_a))
plt.axhline(0); plt.axvline(0)
plt.xlabel("r");
plt.ylabel("x*");
plt.title("Transcritical bifurcation; a = 1");

Let's now consider an equation with two parameters. The presence of two parameters implies that changing the two parameters might lead to the changing of the stable points and their stabilty. The snippet below shows how the two parameters can be passed to a function and then how the main snipped can use two loops over the parameter space to draw the bifurcation diagram in 2D.

In [6]:
def f(x, a, b):
    return x*(1-x**2) - a*(1-np.exp(-b*x));

def dfdx(x, a, b):
    return 1-3*x**2 -a*b*np.exp(-b*x);


a = np.linspace(-2, 2, 100);
b = np.linspace(-2, 2, 100);
[A, B] = np.meshgrid(a, b);
C = 100*np.ones(np.shape(A));

for i in np.arange(0,np.size(a)):
    for j in np.arange(0, np.size(b)):
        sol = fsolve(f, 0, args=(a[i], b[j]), full_output=True)
        if sol[2] == 1: # Solution has convered
            roots = sol[0]
            zeroroot = roots[np.where(np.isclose(roots, 0, atol=1e-8)==True)[0][0]]
            sign_slope_zeroroot = np.sign(dfdx(zeroroot, a[i], b[j]))
            #print(sign_slope_zeroroot)
            C[j,i] = sign_slope_zeroroot

plt.pcolor(A, B, C); plt.colorbar();
ax = plt.gca(); ax.set_aspect(1);
plt.title("Bifurcation space");
In [7]:
c = [-1, 1e-7, 1]
np.where(np.isclose(c, 0, atol=1e-6)==True)
Out[7]:
(array([1], dtype=int64),)
In [ ]: