DynamicalSystemsWithApplicationsUsingPython 2ed Lynch PDF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 104

Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

DYNAMICAL SYSTEMS WITH APPLICATIONS USING PYTHON


Copyright: Springer International Publishing, 2018
Dr Stephen Lynch FIMA SFHEA

Springer book web pages are here: https://www.springer.com/us/book/9783319781440 (https://www.springer.com/us/book


/9783319781440)

IDLE Python Programs

1 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [1]: # Define the logistic map function - save file as fmu.py.


# Run the Module (or type F5).
"""
You can write your own text here.

Created on Tue Jan 23 09:23:47 2018

@author: sladmin
"""
def fmu(mu, x):
return mu * x * (1 - x)

In [2]: fmu(3,0.2)

Out[2]: 0.4800000000000001

In [3]: # Define a function to convert degrees Fahrenheit to Kelvin.


# Save file as F2K.py.
# Run the Module (or type F5).
def F2K():
F = int(input('Enter temperature in degrees Fahrenheit: '))
K = (F + 459.67) * 5 / 9
print('Temperature in Kelvin is {} K'.format(K))

In [4]: F2K()

Enter temperature in degrees Fahrenheit: 50


Temperature in Kelvin is 283.15 K

In [5]: # Define a function to list the first n terms of the Fibonacci sequence.
# Save file as fibonacci.py.
# Run the Module (or type F5).
def fibonacci(n):
a, b = 0, 1
print(a), print(b), print(a + b)
for i in range(n - 3):
a, b = b, a + b
print(a + b)

In [6]: fibonacci(10)

0
1
1
2
3
5
8
13
21
34

2 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [7]: # Define a function that sums the natural numbers to N.


# Save file as sumN.py.
# Run the Module (or type F5).
def sumN(n):
sum = 0
i = 1
while i <= n:
sum += i
i += 1 # update counter

print('The sum is', sum)

In [8]: sumN(100)

The sum is 5050

In [9]: # Euclid's algorithm to find the greatest common divisor.


# See Exercise 10.
# Run the Module (or type F5).

a = 12348
b = 14238

while b != 0:
d = a % b
a = b
b = d

print('The greatest common divisor is {}'.format(a))

The greatest common divisor is 126

In [10]: # A program to grade student results.


# Run the Module (or type F5).

def grade(score):
if score >= 70:
letter = 'A'
elif score >= 60:
letter = 'B'
elif score >= 50:
letter = 'C'
elif score >= 40:
letter = 'D'
else:
letter = 'F'
return letter

In [11]: grade(75)

Out[11]: 'A'

3 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [12]: # Guess the number game.


# Save file as GuessNumber.
# Run the Module (or type F5).

import random # Import the random module.

num_guesses = 0
name = input('Hi! What is your name? ')
number = random.randint(1, 20) # A random integer between 1 and 20.
print('Welcome, {}! I am thinking of an integer between 1 and 20.'.format(name)
)

while num_guesses < 6:


guess = int(input('Take a guess and type the integer? '))
num_guesses += 1

if guess < number:


print('Your guess is too low.')
if guess > number:
print('Your guess is too high.')
if guess == number:
break

if guess == number:
print('Well done {}! You guessed my number in {} guesses!'.format(name, num
_guesses))
else:
print('Sorry, you lose! The number I was thinking of was {}'.format(number)
)

Hi! What is your name? Stephen


Welcome, Stephen! I am thinking of an integer between 1 and 20.
Take a guess and type the integer? 10
Your guess is too low.
Take a guess and type the integer? 15
Your guess is too high.
Take a guess and type the integer? 13
Your guess is too high.
Take a guess and type the integer? 12
Your guess is too high.
Take a guess and type the integer? 11
Well done Stephen! You guessed my number in 5 guesses!

4 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [13]: # A program to plot a color fractal tree.


# Run Module and type >>> FractalTreeColor(200,10) in Python Shell.
# Run the Module (or type F5).
from turtle import *
setheading(90) # The turtle points straight up.
penup() # Lift the pen.
setpos(0,-250) # Set initial point.
pendown() # Pen down.

def FractalTreeColor(length, level):


"""
Draws a fractal tree
"""
pensize(length/10) # Thickness of lines.
if length < 20:
pencolor("green")
else:
pencolor("brown")

speed(0)
if level > 0:
fd(length) # Forward.
rt(30) # Right turn 30 degrees.
FractalTreeColor(length*0.7, level-1)
lt(90) # Left turn 90 degrees.
FractalTreeColor(length*0.5, level-1)
rt(60) # Right turn 60 degrees.
penup()
bk(length) # Backward.
pendown()

In [14]: FractalTreeColor(200,10)

5 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [15]: # Koch square fractal.


# Run the Module (or type F5).

from turtle import *


def KochSquare(length, level): # KochSquare function.
speed(0) # Fastest speed.
for i in range(4):
PlotSide(length, level)
rt(90)

def PlotSide(length, level): # PlotSide function.


if level==0:
fd(length)
return
PlotSide(length/3, level-1)
lt(90)
PlotSide(length/3 ,level-1)
rt(90)
PlotSide(length/3, level-1)
rt(90)
PlotSide(length/3, level-1)
lt(90)
PlotSide(length/3, level-1)

In [16]: KochSquare(200,4)

6 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [17]: # Sierpinski triangle.


# See Figure 1.11.
# Run the Module (or type F5).

from turtle import *


def Sierpinski(length, level): # Function.
speed(0) # Fastest speed.
if level==0:
return
begin_fill() # Fill shape.
color("red")

for i in range(3):
Sierpinski(length/2, level-1)
fd(length)
lt(120) # Left turn 120 degrees.
end_fill()

In [18]: Sierpinski(200,5)

Anaconda Spyder Python Programs

7 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [19]: # Program 01a: A program that solves a simple Ordinary Differential Equation (O
DE).
# See Example 10.

from sympy import dsolve, Eq, symbols, Function


t=symbols('t')
x=symbols('x',cls=Function)
deqn1=Eq(x(t).diff(t),1-x(t))
sol1=dsolve(deqn1,x(t))
print(sol1)

Eq(x(t), C1*exp(-t) + 1)

8 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [20]: # Program 01b: A program that solves a second order ODE.


from sympy import Function, Eq, dsolve, symbols, exp
t=symbols('t')
y=symbols('y',cls=Function)
deqn2=Eq(y(t).diff(t,t) + y(t).diff(t) + y(t), exp(t))
sol2 = dsolve(deqn2, y(t))
print(sol2)

Eq(y(t), (C1*sin(sqrt(3)*t/2) + C2*cos(sqrt(3)*t/2))/sqrt(exp(t)) + exp(t)/3)

In [22]: # Program 01c: Two curves on one plot.


# See Figure 1.14.

import matplotlib.pyplot as plt


import numpy as np

t = np.arange(0.0, 2.0, 0.01)


c=1+np.cos(2*np.pi*t)
s = 1 + np.sin(2*np.pi*t)
plt.plot(t,s,'r--',t,c,'b-.')

plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('Voltage-time plot')
plt.grid(True)
plt.savefig("Voltage-Time Plot.png")
plt.show()

9 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [23]: # Program 01d: Subplots.


# See Figure 1.15.

import matplotlib.pyplot as plt


import numpy as np

def f(t):
return np.exp(-t) * np.cos(2*np.pi*t)

t1=np.arange(0.0, 5.0, 0.1)


t2=np.arange(0.0, 5.0, 0.02)

plt.figure(1)
plt.subplot(211) #subplot(num rows,num cols,fig num)
plt.plot(t1,f(t1),'bo',t2,f(t2),'k',label='damping')
plt.xlabel('time (s)')
plt.ylabel('amplitude (m)')
plt.title('Damped pendulum')
legend = plt.legend(loc='upper center',shadow=True)

plt.subplot(212)
plt.plot(t2, np.cos(2*np.pi*t2),'g--',linewidth=4)
plt.xlabel('time (s)')
plt.ylabel('amplitude (m)')
plt.title('Undamped pendulum')
plt.subplots_adjust(hspace=0.8)

plt.show()

10 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [24]: # Program 01e: Surface and contour plots.


# See Figure 1.16.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D

alpha=0.7
phi_ext=2*np.pi*0.5

def flux_qubit_potential(phi_m,phi_p):
return 2+alpha-2*np.cos(phi_p)*np.cos(phi_m)-alpha*np.cos(phi_ext-2*phi_p)

phi_m=np.linspace(0,2*np.pi,100)
phi_p=np.linspace(0,2*np.pi,100)
X,Y=np.meshgrid(phi_p,phi_m)
Z=flux_qubit_potential(X,Y).T

fig=plt.figure(figsize=(8,6))

ax=fig.add_subplot(1,1,1,projection='3d')
p=ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)
ax.plot_surface(X,Y,Z,rstride=4,cstride=4,alpha=0.25)
cset=ax.contour(X,Y,Z,zdir='z',offset=-np.pi,cmap=plt.cm.coolwarm)
cset=ax.contour(X,Y,Z,zdir='x',offset=-np.pi,cmap=plt.cm.coolwarm)
cset=ax.contour(X,Y,Z,zdir='y',offset=3*np.pi,cmap=plt.cm.coolwarm)

ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);
ax.set_xlabel('$\phi_p$',fontsize=15)
ax.set_ylabel('$\phi_m$',fontsize=15)
ax.set_zlabel('Potential',fontsize=15)
plt.tick_params(labelsize=15)
ax.set_title("Surface and contour plots",fontsize=15)
plt.show()

11 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [25]: # Program 01f: Parametric curve in 3D.


# See Figure 1.17.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig=plt.figure(figsize=(8,6))
ax=fig.add_subplot(1,1,1,projection='3d')

t = np.linspace(-10,10,1000)
x = np.sin(t)
y = np.cos(t)
z = t
ax.plot(x, y, z)
ax.set_xlabel("X Axis")
ax.set_ylabel("Y Axis")
ax.set_zlabel("Z Axis")
ax.set_title("3D Parametric Curve")

plt.show()

12 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 01g: Animation of a simple curve.


# Hit the green play button (Run file (F5)).

# Run %matplotlib qt5 in IPython console before animating.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation

fig = plt.figure()
ax = plt.axes(xlim=(0, 2),ylim=(-2, 2))
line, = ax.plot([],[],lw=2)
plt.xlabel('time')
plt.ylabel('sin($\omega$t)')

def init():
line.set_data([],[])
return line,

# The function to animate.


def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2*np.pi*(0.1*x*i))
line.set_data(x, y)
return line,

# Note: blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init, \
frames=100, interval=200, blit=False)

In [26]: # Program 02a: A separable ODE.


from sympy import *
t=symbols('t')
x=symbols('x',cls=Function)
sol=dsolve(Eq(x(t).diff(t), -t/x(t)), x(t))
print(sol)

[Eq(x(t), -sqrt(C1 - t**2)), Eq(x(t), sqrt(C1 - t**2))]

13 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [27]: # Program 02b: The logistic ODE.


from sympy import *
t=symbols('t'); a=symbols('a'); b=symbols('b')
P=symbols('P',cls=Function)
sol=dsolve(Eq(P(t).diff(t), P(t)*(a-b*P(t))), P(t))
print(sol)

Eq(P(t), a*exp(a*(C1 + t))/(b*(exp(a*(C1 + t)) - 1)))

In [28]: # Program 02c : Power series solution of first order ODE.


# See Example 7.
from sympy import dsolve, Function, pprint
from sympy.abc import t
x=Function("x")
ODE1=x(t).diff(t) + t*x(t) - t**3
pprint(dsolve(ODE1, hint='1st_power_series', n = 8, ics = {x(0):1}))

2 4 6
t 3⋅t t ⎛ 8⎞
x(t) = 1 - ── + ──── - ── + O⎝t ⎠
2 8 16

In [29]: # Program 02d : Power series solution of second order ODE.


# See Example 8.
from sympy import dsolve, Function, pprint
from sympy.abc import t
x=Function("x")
ODE2=x(t).diff(t,2) + t**2*x(t).diff(t) - x(t)
pprint(dsolve(ODE2,hint = '2nd_power_series_ordinary', n=6))

⎛ 4 2 ⎞ ⎛ 3 2 ⎞
⎜t t ⎟ ⎜ t t ⎟ ⎛ 6⎞
x(t) = C₂⋅⎜── + ── + 1⎟ + C₁⋅t⋅⎜- ── + ── + 1⎟ + O⎝t ⎠
⎝24 2 ⎠ ⎝ 12 6 ⎠

14 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [30]: # Program 02e: Numerical and truncated series solutions.


# See Figure 2.6.
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import numpy as np

def ODE2(X, t):


x = X[0]
y = X[1]
dxdt = y
dydt = x - t**2*y
return [dxdt, dydt]

X0 = [1, 0]
t = np.linspace(0, 10, 1000)

sol = odeint(ODE2, X0, t)

x = sol[:, 0]
y = sol[:, 1]

fig, ax = plt.subplots()
ax.plot(t,x,label='Numerical')
ax.plot(t, 1 + t**2/2 + t**4/24,'r-', label='Truncated series')
plt.xlabel("t",fontsize=15)
plt.ylabel("x",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(0,4)
plt.ylim(0,4)

legend = ax.legend(loc='lower center', shadow=True)


plt.show()

In [31]: # Program 2f: A linear first order ODE.


from sympy import Function, dsolve, Eq, symbols, sin
t=symbols('t');
I=symbols('I', cls=Function)
sol=dsolve(Eq(I(t).diff(t), 5*sin(t) - I(t)/5), I(t))
print(sol)

Eq(I(t), (C1 + 25*exp(t/5)*sin(t)/26 - 125*exp(t/5)*cos(t)/26)*exp(-t/5))

15 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [32]: # Program 02g: A second order ODE.


from sympy import symbols, dsolve, Function,Eq, sin
t=symbols('t');
I=symbols('I', cls=Function)
sol=dsolve(Eq(I(t).diff(t,t) + 5*I(t).diff(t) + 6*I(t), 10*sin(t)), I(t))
print(sol)

Eq(I(t), C1*exp(-3*t) + C2*exp(-2*t) + sin(t) - cos(t))

16 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [34]: # Program 02h: Chemical kinetics - conservation of mass.


# See Exercise 7, the reaction: A -> B -> C.

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# Set parameters and initial conditions


r1, r2 = 0.01, 0.02
x0, y0, z0 = 1000, 0, 0

# Maximum time point and total number of time points


tmax, n = 500, 10000

def Chemical_Kinetics(X, t, r1, r2):


#The Differential Equations
x, y, z = X
dx = -r1 * x
dy = r1 * x - r2 * y
dz = r2 * y
return (dx, dy, dz)

# Integrate differential equations on the time grid t.


t = np.linspace(0, tmax, n)
f = odeint(Chemical_Kinetics, (x0, y0, z0), t, args=(r1, r2))
x, y, z = f.T

plt.figure(1)
plt.xlabel('Time')
plt.ylabel('Concentrations')
plt.title('Chemical Kinetics')
plt.plot(t, x, label='|A|')
plt.plot(t, y, label='|B|')
plt.plot(t, z, label='|C|')
legend = plt.legend(loc='right center')
plt.show()

17 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [35]: # Program 03a: Phase portrait of a linear system.


# See Figure 3.8(a).

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint
import pylab as pl

# The 2-dimensional linear system.


a, b, c, d = 2, 1, 1, 2
def dx_dt(x, t):
return [a*x[0] + b *x[1], c*x[0] + d*x[1]]

# Trajectories in forward time.


ts = np.linspace(0, 4, 100)
ic = np.linspace(-1, 1, 5)
for r in ic:
for s in ic:
x0 = [r, s]
xs = odeint(dx_dt, x0, ts)
plt.plot(xs[:,0], xs[:,1], "r-")

# Trajectories in backward time.


ts = np.linspace(0, -4, 100)
ic = np.linspace(-1, 1, 5)
for r in ic:
for s in ic:
x0 = [r, s]
xs = odeint(dx_dt, x0, ts)
plt.plot(xs[:,0], xs[:,1], "r-")

# Label the axes and set fontsizes.


plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(-1,1)
plt.ylim(-1,1)

# Plot the vectorfield. See lines 10, 12 for system.


X,Y = np.mgrid[-1:1:10j,-1:1:10j]
u=a*X + b*Y
v=c*X + d*Y
pl.quiver(X,Y,u,v, color='b')
plt.show()

18 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [36]: # Program 03b: Nonlinear system, phase portrait with vector plot.
# See Figure 3.12.

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint
import pylab as pl

# The 2-dimensional nonlinear system.


def dx_dt(x, t):
return [x[1], x[0]*(1-x[0]**2) + x[1]]

# Trajectories in forward time.


ts = np.linspace(0, 10, 500)
ic = np.linspace(-3, 3, 6)
for r in ic:
for s in ic:
x0 = [r, s]
xs = odeint(dx_dt, x0, ts)
plt.plot(xs[:,0], xs[:,1], "r-")

# Trajectories in backward time.


ts = np.linspace(0, -10, 500)
ic = np.linspace(-3, 3, 6)
for r in ic:
for s in ic:
x0 = [r, s]
xs = odeint(dx_dt, x0, ts)
plt.plot(xs[:,0], xs[:,1], "r-")

# Label the axes and set fontsizes.


plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(-3,3)
plt.ylim(-3,3);

# Plot the vectorfield.


X,Y=np.mgrid[-3:3:20j, -3:3:20j]
u=Y
v=X*(1 - X**2) + Y
pl.quiver(X, Y, u, v, color='b')
plt.show()

19 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [37]: # Program 03c: Finding critical points. Check by plotting the curves of interse
ction.
# See Example 9.
import sympy as sm

x, y = sm.symbols('x, y')
P = x*(1 - x/2 - y)
Q = y*(x - 1 - y/2)

# Set P(x,y)=0 and Q(x,y)=0.


Peqn = sm.Eq(P, 0)
Qeqn = sm.Eq(Q, 0)

# Locate critical points.


criticalpoints = sm.solve((Peqn, Qeqn), x, y)
print(criticalpoints)

[(0, -2), (0, 0), (6/5, 2/5), (2, 0)]

20 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [38]: # Program 04a: Holling-Tanner model. See Figures 4.5 and 4.6.
# Time series and phase portrait for a predator-prey system.
# An isolated periodic solution (limit cycle).
import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt

# The Holling-Tanner model.


def Holling_Tanner(X, t=0):
# here X[0] = x and X[1] = y
return np.array([ X[0]*(1-X[0]/7)-6*X[0]*X[1]/(7+7*X[0]), 0.2*X[1]*(1-0.5*X
[1]/X[0]) ])

t = np.linspace(0, 200, 1000)


# initial values: x0 = 7, y0 = 0.1
Sys0 = np.array([7, 0.1])

X, infodict = integrate.odeint(Holling_Tanner,Sys0,t,full_output=True)
x,y = X.T

fig = plt.figure(figsize=(15,5))
fig.subplots_adjust(wspace = 0.5, hspace = 0.3)
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

ax1.plot(t,x, 'r-',label='prey')
ax1.plot(t,y, 'b-',label='predator')
ax1.set_title("Time Series")

ax1.set_xlabel("time")
ax1.grid()
ax1.legend(loc='best')

ax2.plot(x, y, color="blue")
ax2.set_xlabel("x")
ax2.set_ylabel("y")
ax2.set_title("Phase portrait")
ax2.grid()
plt.show()

21 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [39]: # Program 04b: Predator-prey phase portrait.


# See Exercise 5(a): Co-existence of species at a single critical point.

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint
import pylab as pl

def dx_dt(x, t):


return [x[0]*(4-x[1]-x[0]), x[1]*(3*x[0]-1-x[1])]

ts = np.linspace(0, 20, 500)


xs = odeint(dx_dt, [4,0.01], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-')
xs = odeint(dx_dt, [0.5,7], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-')
xs = odeint(dx_dt, [0.01,0], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-',linewidth=3)
xs = odeint(dx_dt, [6,2], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-')
xs = odeint(dx_dt, [0,7], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-',linewidth=3)
xs = odeint(dx_dt, [6,0], ts)
plt.plot(xs[:, 0], xs[:, 1], 'r-',linewidth=3)
# Label the axes and set fontsizes.
plt.xlabel('x', fontsize=15)
plt.ylabel('y', fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(0, 6)
plt.ylim(0, 7)
# Plot the vectorfield.
X, Y = np.mgrid[0:6:10j, 0:7:10j]
u = X*(4-X-Y)
v = Y*(3*X-1-Y)
pl.quiver(X, Y, u, v, color='b')
plt.show()

22 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [40]: # Program 05a: Limit cycle for Fitzhugh-Nagumo.


# See Figure 5.3.
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint
theta=0.14;omega=0.112;gamma=2.54;epsilon=0.01;
xmin=-0.5;xmax=1.5;ymin=0;ymax=0.3;
def dx_dt(x, t):
return [-x[0]*(x[0]-theta)*(x[0]-1)-x[1]+omega, epsilon*(x[0]-gamma*x[1])]

# Trajectories in forward time.


xs=odeint(dx_dt,[0.5,0.09],np.linspace(0,100,1000))
plt.plot(xs[:,0],xs[:,1], "r-")

# Label the axes and set fontsizes.


plt.xlabel("u",fontsize=15)
plt.ylabel("v",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax);

# Plot the nullclines where dx/dt and dy/dt are zero.


x=np.arange(xmin,xmax,0.01)
plt.plot(x, x/gamma, 'b--', x, -x*(x-theta)*(x-1)+omega,'b--')
plt.show()

23 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [41]: # Program 05b: Example 7, approximate solutions.


# See Figure 5.9.

from scipy.integrate import odeint


import matplotlib.pyplot as plt
import numpy as np

eps=0.3

def ODE(x, t):


return eps*x**2 - x

x0 = 2
t = np.linspace(0, 10, 1000)

sol = odeint(ODE, x0, t)


x = np.array(sol).flatten()

plt.plot(t,x,label='x(t)')
plt.plot(t,2*np.exp(-t),label='O(1)')
plt.plot(t,2*np.exp(-t)+4*eps*(np.exp(-t)-np.exp(-2*t)),label='O($\epsilon $)')
plt.plot(t,2*np.exp(-t)+4*eps*(np.exp(-t)-np.exp(-2*t))+ \
eps**2*8*(np.exp(-t)-2*np.exp(-2*t)+np.exp(-3*t)),label='O($\epsilon^2
$)')

plt.xlabel('t', fontsize=15)
plt.ylabel('x', fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(0, 8)
plt.ylim(0, 2.1)
plt.legend()

plt.show()

24 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [42]: # Program 05c: Error between xN and x0. See Figure 5.9.
# Error between one term solution and numerical solution.

from scipy.integrate import odeint


import matplotlib.pyplot as plt
import numpy as np

def dx_dt(x,t):
return [x[1], 0.01*x[0]**3 - x[0]]
x0=[1,0]
ts=np.linspace(0,100,2000)
xs=odeint(dx_dt,x0,ts)
xN=xs[:,0]

xpert0=np.cos(ts)
plt.plot(ts,xN-xpert0)
plt.xlabel('t')
plt.ylabel('$x_N-x_0$')
plt.show()

25 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [43]: # Program 05d: The Lindstedt-Poincare Method


# Deriving the order epsilon equations.
# See Example 9.

from sympy import collect,expand, Function, Symbol


x0=Function('x0');x1=Function('x1');x2=Function('x2');
x=Function('x')
t=Symbol('t');eps=Symbol('eps');
w1=Symbol('w1');w2=Symbol('w2');
x=x0(t) + eps*x1(t) + eps**2*x2(t)
expr=(1 + eps*w1 + eps**2*w2)**2*x.diff(t,t) + x - eps*x**3
expr=expand(expr)
expr=collect(expr,eps)
print(expr)

-eps**7*x2(t)**3 + eps**6*(w2**2*Derivative(x2(t), (t, 2)) - 3*x1(t)*x2(t)**2)


+ eps**5*(2*w1*w2*Derivative(x2(t), (t, 2)) + w2**2*Derivative(x1(t), (t, 2)) -
3*x0(t)*x2(t)**2 - 3*x1(t)**2*x2(t)) + eps**4*(w1**2*Derivative(x2(t), (t, 2))
+ 2*w1*w2*Derivative(x1(t), (t, 2)) + w2**2*Derivative(x0(t), (t, 2)) + 2*w2*De
rivative(x2(t), (t, 2)) - 6*x0(t)*x1(t)*x2(t) - x1(t)**3) + eps**3*(w1**2*Deriv
ative(x1(t), (t, 2)) + 2*w1*w2*Derivative(x0(t), (t, 2)) + 2*w1*Derivative(x2(t
), (t, 2)) + 2*w2*Derivative(x1(t), (t, 2)) - 3*x0(t)**2*x2(t) - 3*x0(t)*x1(t)*
*2) + eps**2*(w1**2*Derivative(x0(t), (t, 2)) + 2*w1*Derivative(x1(t), (t, 2))
+ 2*w2*Derivative(x0(t), (t, 2)) - 3*x0(t)**2*x1(t) + x2(t) + Derivative(x2(t),
(t, 2))) + eps*(2*w1*Derivative(x0(t), (t, 2)) - x0(t)**3 + x1(t) + Derivative(
x1(t), (t, 2))) + x0(t) + Derivative(x0(t), (t, 2))

In [44]: # Program 06a: Contour plot. See Figure 6.2(a).


import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-10.0,10.0, 100)


ylist = np.linspace(-4.0, 4.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = Y**2/2 - 5*np.cos(X)
plt.figure()
plt.contour(X,Y,Z)
plt.xlabel(r'$\theta$',fontsize=20)
plt.ylabel(r'$\phi$',fontsize=20)
plt.tick_params(labelsize=20)
plt.show()

26 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [45]: # Program 06b: Surface plot of Hamiltonian. See Figure 6.2(b).


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D

def fun(x, y):


return y**2/2 - 5*np.cos(x)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(-10.0, 10.0, 0.1)
y = np.arange(-4.0, 4.0, 0.1)
X, Y = np.meshgrid(x, y)
zs = np.array([fun(x,y) for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)

ax.plot_surface(X, Y, Z)

ax.set_xlabel(r'$\theta$',fontsize=12)
ax.set_ylabel(r'$\phi$',fontsize=12)
ax.set_zlabel(r'$H(\theta,\phi)$',fontsize=12)
plt.tick_params(labelsize=12)
ax.view_init(30, -70)
plt.show()

27 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 07a: Animation of a simple curve. Saddle-node bifurcation.


# See Figure 7.2.
# Animation of mu-x**2, as mu increases from mu=-3 to mu=3.
# Type - %matplotlib qt5 - in Console window.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation

# Set up the figure.


fig=plt.figure();xmin=-4;xmax=4;mu_min=-3;mu_max=3;
ax=plt.axes(xlim=(xmin,xmax),ylim=(xmin,xmax))
line,=ax.plot([],[],lw=2)
ax.plot([xmin,xmax],[0,0],'m')
ax.plot([0,0],[xmin,xmax],'m')

def init():
line.set_data([],[])
return line,

# Animate mu-x^**2, where -3<mu<3.


def animate(mu):
x = np.linspace(xmin,xmax,100)
y = mu-x**2
line.set_data(x, y)
return line,

bifurcation=animation.FuncAnimation(fig,animate,init_func=init,
frames=np.linspace(mu_min,mu_max,1000),interval=10,blit=False)

plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)

plt.show()

28 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 07b.py. Animation.


# Hopf Bifurcation of a limit cycle from a critical point.
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from scipy.integrate import odeint

fig=plt.figure()
myimages=[]

def Hopf(x, t):


return [x[1]+mu*x[0]-x[0]*x[1]**2, mu*x[1]-x[0]-x[1]**3]

time = np.arange(0, 200, 0.01)


x0=[1,0]
for mu in np.arange(-1, 1, 0.1):
xs = odeint(Hopf, x0, time)
imgplot = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot)

my_anim = animation.ArtistAnimation(fig,myimages,interval=100,blit=False,repeat
_delay=100)
plt.show()

29 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 07c: Animation of a Saddle Node on an Invariant Circle (SNIC) bifurca
tion.
# See Figure 7.12.
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from scipy.integrate import odeint
fig=plt.figure()
myimages=[]
def SNIC(x, t):
return [x[0]*(1-x[0]**2-x[1]**2)-x[1]*(1+mu+x[0]),
x[1]*(1-x[0]**2-x[1]**2)+x[0]*(1+mu+x[0])]

time = np.arange(0, 200, 0.01)


x0=[0.5,0]
for mu in np.arange(-3, 1, 0.1):
xs = odeint(SNIC, x0, time)
imgplot = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot)

my_anim = animation.ArtistAnimation(fig,myimages,interval=100,blit=False,repeat
_delay=100)
plt.show()

30 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [46]: # Program 08a: The Rossler chaotic attractor. See Fig. 8.10(a).
# In this case, iteration is used to solve the ODEs.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def Rossler(x,y,z,a=0.2,b=0.2,c=6.3):
x_dot = - y - z
y_dot = x + a*y
z_dot = b + x*z - c*z
return x_dot, y_dot, z_dot

dt = 0.01
stepCnt = 50000

xs=np.empty((stepCnt+1,))
ys=np.empty((stepCnt+1,))
zs=np.empty((stepCnt+1,))

# The initial conditions.


xs[0],ys[0],zs[0] = (1.0,1.0,1.0)

# Iterate.
for i in range(stepCnt):
x_dot,y_dot,z_dot = Rossler(xs[i],ys[i],zs[i])
xs[i+1]=xs[i] + (x_dot*dt)
ys[i+1]=ys[i] + (y_dot*dt)
zs[i+1] =zs[i] + (z_dot*dt)

fig=plt.figure()
ax=Axes3D(fig)

ax.plot(xs, ys, zs, lw=0.5)


ax.set_xlabel("x", fontsize=15)
ax.set_ylabel("y", fontsize=15)
ax.set_zlabel("z", fontsize=15)
plt.tick_params(labelsize=15)
ax.set_title("Rossler Attractor", fontsize=15)

plt.show()

31 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [47]: # Program 08b: The Lorenz attractor. See Figure 8.11.


# In this case, the odeint numerical solver was used to solve the ODE.

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Lorenz paramters and initial conditions


sigma, beta, rho = 10, 2.667, 28
x0, y0, z0 = 0, 1, 1.05

# Maximum time point and total number of time points


tmax, n = 100, 10000

def Lorenz(X, t, sigma, beta, rho):


"""The Lorenz equations."""
x, y, z = X
dx = -sigma*(x - y)
dy = rho*x - y - x*z
dz = -beta*z + x*y
return dx, dy, dz

# Integrate the Lorenz equations on the time grid t.


t = np.linspace(0, tmax, n)
f = odeint(Lorenz, (x0, y0, z0), t, args=(sigma, beta, rho))
x, y, z = f.T

# Plot the Lorenz attractor using a Matplotlib 3D projection.


fig=plt.figure()
ax = Axes3D(fig)

ax.plot(x, y, z,'b-',lw=0.5)

ax.set_xlabel("x", fontsize=15)
ax.set_ylabel("y", fontsize=15)
ax.set_zlabel("z", fontsize=15)
plt.tick_params(labelsize=15)
ax.set_title("Lorenz Attractor", fontsize=15)

plt.show()

32 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [48]: # Program 08c: The Belousov-Zhabotinski Reaction. See Figure 8.16.


# Plotting time series for a 3-dimensional ODE.

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# B_Z parameters and initial conditions.


q, f, eps, delta = 3.1746e-5, 1, 0.0099, 2.4802e-5
x0, y0, z0 = 0, 0, 0.1

# Maximum time point and total number of time points.


tmax, n = 50, 10000

def B_ZReaction(X,t,q,f,eps,delta):
x, y, z = X
dx = (q*y - x*y + x*(1 - x))/eps
dy = ( - q*y - x*y + f*z)/delta
dz = x - z
return dx, dy, dz

t = np.linspace(0, tmax, n)
f = odeint(B_ZReaction, (x0, y0, z0), t, args=((q,f,eps,delta)))
x, y, z = f.T

# Plot time series.


fig = plt.figure(figsize=(15,5))
fig.subplots_adjust(wspace = 0.5, hspace = 0.3)
ax1 = fig.add_subplot(1,3,1)
ax1.set_title("Relative concentration bromous acid", fontsize=12)
ax2 = fig.add_subplot(1,3,2)
ax2.set_title("Relative concentration bromide ions", fontsize=12)
ax3 = fig.add_subplot(1,3,3)
ax3.set_title("Relative concentration cerium ions", fontsize=12)

ax1.plot(t, x, 'b-')
ax2.plot(t, y, 'r-')
ax3.plot(t, z, 'm-')
plt.show()

33 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Programs 08d: Animation of a Chua circuit bifurcation.


# You can watch a YouTube animation of a physical circuit on the web.
# Search for Chua circuit animated bifurcation.

from matplotlib import pyplot as plt


from matplotlib import animation
import numpy as np
from scipy.integrate import odeint
fig=plt.figure()
myimages=[]

mo=-1/7;m1=2/7;Tmax=100;
def Chua(x, t):
return [a*(x[1]-(m1*x[0]+(mo-m1)/2*(np.abs(x[0]+1)-np.abs(x[0]-1)))),x[0]-x
[1]+x[2],-15*x[1]]

time = np.arange(0, Tmax, 0.1)


x0=[1.96,-0.0519,-3.077]
for a in np.arange(8, 11, 0.1):
xs = odeint(Chua, x0, time)
imgplot = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot)

my_anim=animation.ArtistAnimation(fig,myimages,interval=500,\
blit=False,repeat_delay=500)
plt.show()

34 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [49]: # Program 09a: Poincare first return map.


# See Figure 9.2.
import matplotlib.pyplot as plt
from sympy import sqrt
import numpy as np
from scipy.integrate import odeint
xmin=-1;xmax=1;ymin=-1;ymax=1;
def dx_dt(x, t):
return [-x[1]-x[0]*sqrt(x[0]**2+x[1]**2),x[0]-x[1]*sqrt(x[0]**2+x[1]**2)]

# Phase portrait.
t=np.linspace(0,16*np.pi,10000)
xs=odeint(dx_dt,[1,0],t)
plt.plot(xs[:,0],xs[:,1], "r-")
plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax);
plt.show()

# First eight returns on x-axis.


t=np.linspace(0,9*2*np.pi,900000)
xs=odeint(dx_dt,[1,0],t)
for i in range(9):
print('r_',i,'=',xs[100000*i,0])

r_ 0 = 1.0
r_ 1 = 0.13730247618333363
r_ 2 = 0.0737116398245952
r_ 3 = 0.050378946444256625
r_ 4 = 0.03826617811397822
r_ 5 = 0.03084905202922912
r_ 6 = 0.02584041437408372
r_ 7 = 0.022231002965186188
r_ 8 = 0.019506343238878496

35 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [50]: # Program 09b: Hamiltonian with two degrees of freedom.


# See Figure 9.5(e): quasiperiodic behavior.

import numpy as np
from scipy.integrate import odeint
from sympy import sqrt
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Maximum time point and total number of time points


tmax, n = 100, 20000
w1=sqrt(2);w2=1;

def Hamiltonian4D(X, t):


"""Hamiltonian equations."""
p1, p2, q1, q2 = X
dp1 = -w1*q1
dp2 = -w2*q2
dq1 = w1*p1
dq2 = w2*p2
return dp1, dp2, dq1, dq2

t = np.linspace(0, tmax, n)
f = odeint(Hamiltonian4D, (0.5, 1.5, 0.5, 0), t)
p1, p2, q1, q2 = f.T

fig=plt.figure()
ax = Axes3D(fig)

ax.plot(p1, q1, q2,'b-',lw=0.5)


ax.set_xlabel(r'$p_1$', fontsize=15)
ax.set_ylabel(r'$q_1$', fontsize=15)
ax.set_zlabel(r'$q_2$', fontsize=15)
plt.tick_params(labelsize=12)
ax.set_title("H=1.365416000", fontsize=15)
plt.show()

36 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [51]: # Program 09c: Phase portrait and Poincare section of a nonautonomous ODE.
# See Figure 9.11(b): The Duffing equation.

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint
xmin=-2;xmax=2;ymin=-2;ymax=2;
k=0.3;omega=1.25;Gamma=0.5;
def dx_dt(x, t):
return [x[1], x[0] - k*x[1] - x[0]**3 + Gamma*np.cos(omega*t)]

# Phase portrait.
t=np.linspace(0,500,10000)
xs=odeint(dx_dt,[1,0],t)
plt.plot(xs[:,0],xs[:,1], "r-",lw=0.5)
plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax);
plt.show()

# The Poincare section.


x=[];y=[];

fig, ax = plt.subplots(figsize=(6,6))
t=np.linspace(0,4000*(2*np.pi)/omega,16000000)
xs=odeint(dx_dt,[1,0],t)
for i in range(4000):
x.extend([xs[4000*i,0]])
y.extend([xs[4000*i,1]])

ax.scatter(x,y, color='blue',s=0.1)
plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

37 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

38 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [52]: # Program 09d: Bifurcation diagram of the Duffing equation.


# See Figure 9.14. The system is history dependent.
# This can take about 20 seconds to complie.

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint

k = 0.3
omega = 1.25
alpha = 1
beta = -1

rs_up = []
rs_down = []

def duffing(x, t):


return [x[1],
-beta * x[0] - k*x[1] - alpha * x[0]**3 + gamma * np.cos(omega*t)]

# Take num_steps=4000 to get Figure 9.13.


num_steps = 4002
step = 0.0001
interval = num_steps * step
a, b = 1, 0
ns = np.linspace(0, num_steps, num_steps)

# Ramp the amplitude of vibration, gamma, up.


for n in ns:
gamma = step * n
t = np.linspace(0, (4*np.pi) / omega, 200)
xs = odeint(duffing, [a, b], t)
for i in range(2):
a = xs[100, 0]
b = xs[100, 1]
r = np.sqrt(a**2 + b**2)
rs_up.append([n, r])

rs_up = np.array(rs_up)

# Ramp the amplitude of vibration, gamma, down.


for n in ns:
gamma = interval - step * n
t = np.linspace(0, (4*np.pi) / omega, 200)
xs = odeint(duffing, [a, b], t)
for i in range(2):
a = xs[100, 0]
b = xs[100, 1]
r = np.sqrt(a**2 + b**2)
rs_down.append([num_steps - n, r])

rs_down = np.array(rs_down)

fig, ax = plt.subplots()
xtick_labels = np.linspace(0, interval, 5)
ax.set_xticks([x / interval * num_steps for x in xtick_labels])
ax.set_xticklabels(['{:.1f}'.format(xtick) for xtick in xtick_labels])

plt.plot(rs_up[:, 0], rs_up[:,1], 'r.', markersize=0.1)


plt.plot(rs_down[:, 0], rs_down[:,1], 'b.', markersize=0.1)
plt.xlabel(r'$\Gamma$', fontsize=15)
plt.ylabel('r', fontsize=15)
plt.tick_params(labelsize=15)

39 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [53]: # Program 10a: Computing the Lienard Lyapunov quantities.


from sympy import symbols, solve
a2,a3,a4,a5,b2,b3,b4,b5=symbols('a2 a3 a4 a5 b2 b3 b4 b5')
V30,V21,V12,V03=symbols('V30 V21 V12 V03')
solve([3*V30-2*V12-b2,V12,V21+a2,2*V21-3*V03],[V30,V21,V12,V03])
V40,V31,V22,V13,V04,eta4=symbols('V40 V31 V22 V13 V04 eta4')
V4=solve([4*V40-2*V22-b3+2*a2**2,2*V22-4*V04,-eta4-V31-a3,V22,-2*eta4+3*V31-3*V
13+2*a2*b2,-eta4+V13],\
[V40,V31,V22,V13,V04,eta4])
print(V4)
V50,V41,V32,V23,V14,V05=symbols('V50 V41 V32 V23 V14 V05')
V5=solve([5*V50-2*V32-b4+10*a2**2*b2/3,3*V32-4*V14,V14,-V41-a4+2*a2**3,4*V41-3*
V23+2*a2*b3,2*V23-5*V05],\
[V50,V41,V32,V23,V14,V05])
print(V5)
V60,V51,V42,V33,V24,V15,V06,eta6=symbols('V60 V51 V42 V33 V24 V15 V06 eta6')
V6=solve([6*V60-2*V42-b5+6*a2*a4+4*a2**2*b2**2/3-8*a2**4,\
4*V42-4*V24-16*a2**4/3-4*a2**2*b3/3+8*a2*a4/3,\
V24-6*V06,\
V42+V24,\
-eta6-V51-a5+8*a2**3*b2/3,\
-3*eta6+5*V51-3*V33+2*a2*b4-8*a2**3*b2-2*a2*b2*b3+4*a4*b2,\
-3*eta6+3*V33-5*V15-16*a2**3*b2/3-4*a2*b2*b3/3+8*a4*b2/3,\
-eta6+V15],\
[V60,V51,V42,V33,V24,V15,V06,eta6])
print(V6)

{V40: -a2**2/2 + b3/4, V31: -a2*b2/4 - 5*a3/8, V22: 0, V13: a2*b2/4 - 3*a3/8, V
04: 0, eta4: a2*b2/4 - 3*a3/8}
{V50: -2*a2**2*b2/3 + b4/5, V41: 2*a2**3 - a4, V32: 0, V23: 8*a2**3/3 + 2*a2*b3
/3 - 4*a4/3, V14: 0, V05: 16*a2**3/15 + 4*a2*b3/15 - 8*a4/15}
{V60: 14*a2**4/9 - 2*a2**2*b2**2/9 + a2**2*b3/18 - 10*a2*a4/9 + b5/6, V51: 8*a2
**3*b2/3 + 5*a2*b2*b3/24 - a2*b4/8 - 5*a4*b2/12 - 11*a5/16, V42: a2*(4*a2**3 +
a2*b3 - 2*a4)/6, V33: 16*a2**3*b2/9 - a2*b2*b3/9 + a2*b4/3 + 2*a4*b2/9 - 5*a5/6
, V24: a2*(-4*a2**3 - a2*b3 + 2*a4)/6, V15: -5*a2*b2*b3/24 + a2*b4/8 + 5*a4*b2/
12 - 5*a5/16, V06: a2*(-4*a2**3 - a2*b3 + 2*a4)/36, eta6: -5*a2*b2*b3/24 + a2*b
4/8 + 5*a4*b2/12 - 5*a5/16}

40 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [54]: # Program 10b: Polynomial Reduce. See Example 4.


from sympy import reduced
from sympy.abc import x,y,z
f=x**4+y**4+z**4
p=reduced(f,[x**2+y,z**2*y-1,y-z**2])
print(p)
q=reduced(f,[y-z**2,z**2*y-1,x**2+y])
print(q)

([x**2 - y, y**2 + 2, y**3 + 2*y], z**4 + 2)


([-x**2 + y**3 + y**2*z**2 + y*z**4 + z**6 + z**2, 0, x**2 - z**2], z**8 + 2*z*
*4)

In [55]: # Program 10c: The S-Polynomial. See Example 5.


from sympy import expand, LM, LT, lcm
from sympy.abc import x,y,z
def s_polynomial(f, g):
return expand(lcm(LM(f), LM(g))*(1/LT(f)*f - 1/LT(g)*g))
F=[f, g]=[x-13*y**2-12*z**3, x**2-x*y+92*z]
S=s_polynomial(f,g)
print(S)

-13*x*y**2 + x*y - 12*x*z**3 - 92*z

In [56]: # Program 10d: Computing Groebner bases. See Example 6.


from sympy import groebner
from sympy.abc import x,y
G=groebner([x+y**2-x**3, 4*x**3-12*x*y**2+x**4+2*x**2*y**2+y**4],order='lex')
print(G)

GroebnerBasis([5970075*x + 160356*y**10 + 14472880*y**8 - 162599547*y**6 + 1638


45838*y**4 + 5970075*y**2, y**12 + 90*y**10 - 1037*y**8 + 1278*y**6 - 195*y**4]
, x, y, domain='ZZ', order='lex')

In [57]: # Program 10e: Computing Groebner bases. See Example 7.


# Reducing the first five Lyapunov quantities of a Lienard system.
from sympy import groebner, symbols
a1,a2,a3,a4,b2,b3=symbols('a1 a2 a3 a4 b2 b3')

G=groebner([-a1,2*a2*b2-3*a3,5*b2*(2*a4-b3*a2),\
-5*b2*(92*b2**2*a4-99*b3**2*a2+1520*a2**2*a4-760*a2**3*b3-46*b2**2*b3*a2+198*b3
*a4),\
-b2*(14546*b2**4*a4+105639*a2**3*b3**2+96664*a2**3*b2**2*b3-193328*a2**2*b2**2*
a4-\
891034*a2**4*a4+445517*a2**5*b3+211632*a2*a4**2-317094*a2**2*b3*a4-44190*b2**2*
b3*a4+\
22095*b2**2*b3**2*a2-7273*b2**4*b3*a2+5319*b3**3*a2-10638*b3**2*a4)],order='lex
')

print(G)

GroebnerBasis([a1, 2*a2*b2 - 3*a3, 3*a3*b3 - 4*a4*b2], a1, a2, a3, a4, b2, b3,
domain='ZZ', order='lex')

41 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 10f: First homoclinic limit cycle bifurcation animation. See Figure 1
0.2.
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from scipy.integrate import odeint

fig=plt.figure()
plt.axis([-1.5, 1.5, -1.5, 1.5])
myimages=[]

def Homoclinic1(x, t):


return [x[1]+10*x[0]*(0.1-x[1]**2), -x[0]+C]

time = np.arange(0, 200, 0.01)


x0=[1,0]
for C in np.arange(-0.2, 0.2, 0.01):
xs = odeint(Homoclinic1, x0, time)
imgplot = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot)

my_anim = animation.ArtistAnimation(fig,myimages,interval=100,blit=False,repeat
_delay=100)
plt.show()

42 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 10g: Second homoclinic limit cycle bifurcation. See Figure 10.3.
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from scipy.integrate import odeint

fig=plt.figure()
plt.axis([-2, 0.5, -1, 1])
myimages=[]

def Homoclinic2(x, t):


return [x[1], x[0]+x[0]**2-x[0]*x[1]+L*x[1]]

time = np.arange(0, 50, 0.005)


x0=[-0.1,0.1]
for L in np.arange(-2, -0.5, 0.01):
xs = odeint(Homoclinic2, x0, time)
imgplot2 = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot2)

my_anim = animation.ArtistAnimation(fig,myimages,interval=100,blit=False,repeat
_delay=100)
plt.show()

43 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 11a: Animation of a limit cycle for a Lienard system.


# See Figure 11.12.
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from scipy.integrate import odeint

fig=plt.figure();xmin=-1.5;xmax=1.5;ymin=-5;ymax=5;
ax=plt.axes(xlim=(xmin,xmax),ylim=(ymin,ymax))
myimages=[]

def Lienard(x, t):


return [mu*x[1] - mu*(- 4*x[0] + x[0]**3), - x[0]/mu]

time = np.arange(0, 20, 0.1)


x0=[2,0]
for mu in np.arange(0, 10, 0.01):
xs = odeint(Lienard, x0, time)
imgplot = plt.plot(xs[:,0], xs[:,1], "r-")
myimages.append(imgplot)

my_anim = animation.ArtistAnimation(fig,myimages,interval=100,\
blit=False,repeat_delay=100)
plt.show()

44 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [58]: # Program 11b: Small-amplitude limit cycles.


# A cubic Lienard system. See Figure 10.1 and Table 11.1.
# Limit cycles are shown as blue trajectories.

import matplotlib.pyplot as plt


import numpy as np
from scipy.integrate import odeint

a1, a2, a3, b2, b3 = 0.01, 1, 1/3, 1, 2


xmin, xmax, ymin, ymax = -1, 1, -0.6, 1.4
# The Lienard system
def Lienard(x, t):
# Here x[0] = x and x[1] = y
return np.array([ x[1] - a1*x[0] - a2*x[0]**2 - a3*x[0]**3, \
-x[0] - a1*x[1] - b2*x[0]**2 - b3*x[0]**3 ])

t = np.linspace(0, 200, 1000)

# Trajectories in forward time move away from inner limit cycle.


xs=odeint(Lienard,[0.25,0],np.linspace(0,20,5000))
plt.plot(xs[:,0],xs[:,1], "r-")

# Unstable limit cycle.


# Trajectories in backwards time move towards the limit cycle.
xs=odeint(Lienard,[0.295,0],np.linspace(0,-50,5000))
plt.plot(xs[:,0],xs[:,1], 'b-', linewidth=2)

# Trajectories in forward time move away from inner limit cycle.


xs=odeint(Lienard,[0.32,0],np.linspace(0,20,5000))
plt.plot(xs[:,0],xs[:,1], 'r-')

# Trajectories in forward time move towards the outer limit cycle.


xs=odeint(Lienard,[0.44,0],np.linspace(0,22,5000))
plt.plot(xs[:,0],xs[:,1], 'r-')

# Stable limit cycle.


xs=odeint(Lienard,[0.519,0],np.linspace(0,50,5000))
plt.plot(xs[:,0],xs[:,1], 'b-', linewidth=2)

# Trajectories in forward time move towards the outer limit cycle.


xs=odeint(Lienard,[0.6,0],np.linspace(0,22,5000))
plt.plot(xs[:,0],xs[:,1], 'r-')

# Label the axes and set fontsizes.


plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax);
plt.show()

45 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [59]: # Program 12a: The method of steps.


# See Figure 12.1.
from sympy import integrate,symbols
xi,t,i=symbols('xi t i')

def phi(i,t):
if i==0:
return 1 # Initial history x(t)=1 on [-1,0].
else:
return phi(i-1,i-1)-integrate(phi(i-1,xi-1),(xi,i-1,t))

x=[]
tmax=10;
for j in range(tmax+1):
p=phi(j,t)
x.append(p)

print('x(t)=',x)

x(t)= [1, -t + 1, t**2/2 - 2*t + 3/2, -t**3/6 + 3*t**2/2 - 4*t + 17/6, t**4/24
- 2*t**3/3 + 15*t**2/4 - 17*t/2 + 149/24, -t**5/120 + 5*t**4/24 - 2*t**3 + 109*
t**2/12 - 115*t/6 + 1769/120, t**6/720 - t**5/20 + 35*t**4/48 - 197*t**3/36 + 1
061*t**2/48 - 1085*t/24 + 26239/720, -t**7/5040 + 7*t**6/720 - t**5/5 + 107*t**
4/48 - 521*t**3/36 + 13081*t**2/240 - 13201*t/120 + 463609/5040, t**8/40320 - t
**7/630 + 7*t**6/160 - 487*t**5/720 + 3685*t**4/576 - 27227*t**3/720 + 39227*t*
*2/288 - 39371*t/144 + 3157891/13440, -t**9/362880 + t**8/4480 - t**7/126 + 701
*t**6/4320 - 1511*t**5/720 + 51193*t**4/2880 - 212753*t**3/2160 + 1156699*t**2/
3360 - 1158379*t/1680 + 43896157/72576, t**10/3628800 - t**9/36288 + 11*t**8/89
60 - 323*t**7/10080 + 1873*t**6/3456 - 89269*t**5/14400 + 279533*t**4/5760 - 77
61511*t**3/30240 + 23602499*t**2/26880 - 23615939*t/13440 + 5681592251/3628800]

46 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [60]: # Program 12b: Solution of a DDE using the method of steps.


# See Figure 12.1. The plot is a piecewise function.
# The lambda t: functions are computed in Programs 12a.

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(-1, 10, 1000)


plt.plot(t, np.piecewise(t, [t<=0,t>0,t>1,t>2,t>3,t>4,t>5,t>6,t>7,t>8,t>9],
[lambda t: 1,
lambda t: 1-t,
lambda t: t**2/2-2*t+3/2,
lambda t: -t**3/6+3*t**2/2-4*t+17/6,
lambda t: t**4/24-2*t**3/3+15*t**2/4-17*t/2+149/24,
lambda t: -t**5/120 + 5*t**4/24 - 2*t**3 + 109*t**2/12
- 115*t/6 + 1769/120,
lambda t: t**6/720 - t**5/20 + 35*t**4/48 - 197*t**3/3
6
+ 1061*t**2/48 - 1085*t/24 + 26239/720,
lambda t: -t**7/5040 + 7*t**6/720 - t**5/5 + 107*t**4/
48 -
521*t**3/36 + 13081*t**2/240 - 13201*t/120 + 463609/50
40,
lambda t: t**8/40320 - t**7/630 + 7*t**6/160 - 487*t**
5/720 +
3685*t**4/576 - 27227*t**3/720 + 39227*t**2/288 - 3937
1*t/144
+ 3157891/13440,
lambda t: -t**9/362880 + t**8/4480 - t**7/126 + 701*t*
*6/4320 -
1511*t**5/720 + 51193*t**4/2880 - 212753*t**3/2160 + 1
156699*t**2/3360
- 1158379*t/1680 + 43896157/72576,
lambda t: t**10/3628800 - t**9/36288 + 11*t**8/8960 -
323*t**7/10080 +
1873*t**6/3456 - 89269*t**5/14400 + 279533*t**4/5760 -
7761511*t**3/30240 +
23602499*t**2/26880 - 23615939*t/13440 + 5681592251/36
28800
]))

plt.xlabel("t",fontsize=25)
plt.ylabel("x(t)",fontsize=25)
plt.tick_params(labelsize=25)
plt.show()

47 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

48 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 12c: The Mackey-Glass DDE.


# See Figure 12.5(a).
# pydelay must be on your computer.

import pylab as pl
from pydelay import dde23

# define the equations


eqns = {
'x' : '2 * x(t-tau) / (1.0 + pow(x(t-tau),p)) - x'
}

#define the parameters


params = {
'tau': 2,
'p' : 10
}

# Initialise the solver


dde = dde23(eqns=eqns, params=params)

# set the simulation parameters


# (solve from t=0 to t=1000 and limit the maximum step size to 1.0)
dde.set_sim_params(tfinal=1000, dtmax=1.0)

# set the history of to the constant function 0.5 (using a python lambda functi
on)
histfunc = {
'x': lambda t: 0.5
}
dde.hist_from_funcs(histfunc, 51)

# run the simulator


dde.run()

# Make a plot of x(t) vs x(t-tau):


# Sample the solution twice with a stepsize of dt=0.1:

# once in the interval [515, 1000]


sol1 = dde.sample(515, 1000, 0.1)
x1 = sol1['x']

# and once between [500, 1000-15]


sol2 = dde.sample(500, 1000-15, 0.1)
x2 = sol2['x']

pl.plot(x1, x2)
pl.xlabel('$x(t)$')
pl.ylabel('$x(t - 15)$')
pl.show()

49 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

50 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 12d: The Lang-Kobayashi DDEs.


# See Figure 12.10.
# pydelay must be on your computer.
import numpy as np
import pylab as pl
from pydelay import dde23

tfinal = 10000
tau = 1000

#the laser equations


eqns = {
'E:c': '0.5*(1.0+ii*a)*E*n + K*E(t-tau)',
'n' : '(p - n - (1.0 +n) * pow(abs(E),2))/T'
}

params = {
'a' : 4.0,
'p' : 1.0,
'T' : 200.0,
'K' : 0.1,
'tau': tau,
'nu' : 10**-5,
'n0' : 10.0
}

noise = { 'E': 'sqrt(0.5*nu*(n+n0)) * (gwn() + ii*gwn())' }

dde = dde23(eqns=eqns, params=params, noise=noise)


dde.set_sim_params(tfinal=tfinal)

# use a dictionary to set the history


thist = np.linspace(0, tau, tfinal)
Ehist = np.zeros(len(thist))+1.0
nhist = np.zeros(len(thist))-0.2
dic = {'t' : thist, 'E': Ehist, 'n': nhist}

# 'useend' is True by default in hist_from_dict and thus the


# time array is shifted correctly
dde.hist_from_arrays(dic)

dde.run()

t = dde.sol['t']
E = dde.sol['E']
n = dde.sol['n']

spl = dde.sample(-tau, tfinal, 0.1)

pl.plot(t[:-1], t[1:] - t[:-1], '0.8', label='step size')


pl.plot(spl['t'], abs(spl['E']), 'g', label='sampled solution')
pl.plot(t, abs(E), '.', label='calculated points')
pl.legend()

pl.xlabel('$t$')
pl.ylabel('$|E|$')

pl.xlim((0.95*tfinal, tfinal))
pl.ylim((0,3))
pl.show()

51 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [61]: # Program 13a: Recurrence relations, interest in a bank account.


from sympy import Function, rsolve
from sympy.abc import n
x=Function('x');
f=x(n+1)-(1+3/100)*x(n);
sol=rsolve(f,x(n),{x(0):10000});
print('x_n=',sol)
x_5=round(sol.subs(n,5),2)
print('x(5)=£',x_5)

x_n= 10000*1.03**n
x(5)=£ 11592.74

In [62]: # Program 13b: A second order recurrence relation.


# See Example 2.
from sympy import Function, rsolve
from sympy.abc import n
x = Function('x');
f = x(n+2) - x(n+1) - 6*x(n);
sol=rsolve(f, x(n), {x(0):1,x(1):2});
print('x_n=', sol)

x_n= (-2)**n/5 + 4*3**n/5

52 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [63]: # Program 13c: The Leslie matrix. See Example 4.


# Compute the population distribution after 50 years.
# Determine the eigenvalues and eigenvectors of a Leslie matrix.
import numpy as np
import numpy.linalg as LA
L=np.array([[0,3,1],[0.3,0,0],[0,0.5,0]])
X0=np.array([[1000],[2000],[3000]])
X_50=np.dot(LA.matrix_power(L,50),X0)
X_50=X_50.round()
print('X(50)=',X_50)
dL,VL=LA.eig(L)
print('Eigenvalues=',dL)
print('Eigenvectors=',VL)

X(50)= [[15696.]
[ 4604.]
[ 2249.]]
Eigenvalues= [ 1.02304502 -0.85068938 -0.17235564]
Eigenvectors= [[ 0.95064458 -0.92555739 0.18403341]
[ 0.27876913 0.32640259 -0.32032617]
[ 0.1362448 -0.19184593 0.9292593 ]]

53 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [64]: # Program 13d: The Leslie matrix population plot. See Example 4.
# Plot the population distribution for 0<t<50 years.
# In this case, one age class is one year.

import numpy as np
import numpy.linalg as LA
import matplotlib.pyplot as plt

t_span = 51
L=np.array([[0,3,1],[0.3,0,0],[0,0.5,0]])

X=[0]*t_span;X1=[0]*t_span;X2=[0]*t_span;X3=[0]*t_span;
X[0]=np.array([[1000],[2000],[3000]])

for i in range(t_span):
X[i] =np.array(np.dot(LA.matrix_power(L,i),X[0])).tolist()
X1[i] = X[i][0]
X2[i] = X[i][1]
X3[i] = X[i][2]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(X1,color='r',label='Age Class 1')
ax.plot(X2,color='b',label='Age Class 2')
ax.plot(X3,color='k',label='Age Class 3')
plt.xlabel("Age classes",fontsize=15)
plt.ylabel("Populations",fontsize=15)
plt.tick_params(labelsize=15)
legend = plt.legend(loc='upper center',shadow=True)
plt.show()

54 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [65]: # Program 14a: Graphical iteration of the tent map.


# See Figure 14.7(a).
from sympy import Rational
import numpy as np
import matplotlib.pyplot as plt

x=Rational(1,5) # Initial value


inputs = np.array([])
outputs = np.array([])
inputs = np.append(inputs,x)
outputs = np.append(outputs,0)
print(x)
for i in range(2,10):
inputs = np.append(inputs,x)
inputs = np.append(inputs,x)
outputs = np.append(outputs,x)
if x < Rational(1,2):
x = 2 * x
elif x > Rational(1,2):
x = 2 - 2 * x
outputs = np.append(outputs,x)
print(x)
plt.plot(inputs,outputs,lw=2)

# Plot the tent function and line y=x.


X1 = np.linspace(0,0.5,100,endpoint=True)
X2=np.linspace(0.5,1,100,endpoint=True)
X=np.linspace(0,1,200,endpoint=True)
plt.plot(X1,2*X1,'k-')
plt.plot(X2,2*(1-X2),'k-')
plt.plot(X,X,'r-')
plt.xlabel("x",fontsize=15)
plt.ylabel("T(x)",fontsize=15)
plt.tick_params(labelsize=15)

plt.show()

55 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

1/5
2/5
4/5
2/5
4/5
2/5
4/5
2/5
4/5

56 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [66]: # Program 14b: Bifurcation diagram of the logistic map.


# See Figures 14.15 and 14.16.
import numpy as np
import matplotlib.pyplot as plt
def f(x, r):
return r * x * (1-x)

if __name__ == "__main__":
ys = []
rs = np.linspace(0, 4, 2000)
#rs = np.linspace(3.5, 4, 2000) # For Figure 14.16.
for r in rs:
x = 0.1
for i in range(500):
x = f(x, r)
for i in range(50):
x = f(x, r)
ys.append([r, x])

ys = np.array(ys)
plt.plot(ys[:,0],ys[:,1],'r.',markersize=0.05)
plt.xlabel("$\mu$",fontsize=15)
plt.ylabel("x",fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

57 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [67]: # Program 14c: Lyapunov exponents of the logistic map.


# See Figure 14.17.
import numpy as np
import matplotlib.pyplot as plt

Numpoints=16000;
result = []
lambdas = []
maps = []
xmin = 3
xmax = 4
mult=(xmax-xmin)*Numpoints

muvalues = np.arange(xmin, xmax, 20/Numpoints)

for r in muvalues:
x = 0.1
result = []
for t in range(100):
x = r * x * (1 - x)
result.append(np.log(abs(r - 2*r*x)))
lambdas.append(np.mean(result))
# Ignore first 100 iterates.
for t in range(20):
x = r * x * (1 - x)
maps.append(x)

fig = plt.figure(figsize=(8,6))
ax1 = fig.add_subplot(1,1,1)

xticks = np.linspace(xmin, xmax, mult)


zero = [0]*mult
ax1.plot(xticks,zero,'k-',linewidth=3)
ax1.plot(xticks, maps,'r.',alpha = 0.3,label='Logistic map')
ax1.set_xlabel('r')
ax1.plot(muvalues,lambdas,'b-',linewidth= 1,label='Lyapunov exponent')
ax1.grid('on')
ax1.set_ylim(-1, 1)
ax1.set_xlabel('$\mu$',fontsize=15)
ax1.legend(loc='best')
ax1.set_title('Logistic map versus Lyapunov exponent',fontsize=15)
plt.show()

58 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

/anaconda3/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:424: Matplo
tlibDeprecationWarning:
Passing one of 'on', 'true', 'off', 'false' as a boolean is deprecated; use an
actual boolean (True/False) instead.
warn_deprecated("2.2", "Passing one of 'on', 'true', 'off', 'false' as a "

59 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [68]: # Program 14d: Iteration of the Henon Map.


# See Figure 14.23: Chaotic attractor.

import matplotlib.pyplot as plt


# Parameters
a=1.2;b=0.4; # Set a=1 to get Figure 14.23(a).
Num_iterations=10000;

def Henon(X):
x, y = X
xn = 1 - a*x*x + y
yn = b*x
return xn,yn

# Ignore the first 100 iterates.


X0=[(1-b)/2, (1-b)/2]
X,Y=[],[]
for i in range(100):
xn,yn=Henon(X0)
X,Y = X + [xn], Y + [yn]
X0=[xn,yn]

X,Y=[],[]
for i in range(Num_iterations):
xn,yn=Henon(X0)
X, Y = X + [xn], Y + [yn]
X0=[xn,yn]

fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(X,Y,color='blue',s=0.1)
plt.xlabel("x",fontsize=15)
plt.ylabel("y",fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

60 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [69]: # Program 14e: Lyapunov exponents of the Henon map.


# See Exercise 8(c).

import numpy as np

a=1.2;b=0.4;x=0;y=0;
vec1=[1,0];vec2=[0,1];
for i in range(490):
xn = 1 - a*x*x + y
yn = b*x
x=xn;y=yn;
J=np.array([[-2*a*x, 1],[b, 0]])
vec1=J.dot(vec1)
vec2=J.dot(vec2)
dotprod1=np.dot(vec1,vec1)
dotprod2=np.dot(vec1,vec2)
vec2=vec2-np.multiply((dotprod2/dotprod1),vec1)
lengthv1=np.sqrt(dotprod1)
area=np.multiply(vec1[0],vec2[1])-np.multiply(vec1[1],vec2[0])
h1=np.log(lengthv1)/i
h2=np.log(area)/i-h1

print('h_1=',h1)
print('h_2=',h2)

h_1= 0.3391568093091681
h_2= -1.2565387259040743

/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:20: RuntimeWarning
: divide by zero encountered in double_scalars
/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:21: RuntimeWarning
: invalid value encountered in log

61 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [70]: # Programs 14f: Graphical iteration of the logistic map.


# See Figure 14.14.

import numpy as np
import matplotlib.pyplot as plt

x = 0.2 # Initial value


inputs = np.array([x])
outputs = np.array([0])

for i in range(2, 100):


inputs = np.append(inputs, x)
inputs = np.append(inputs, x)
outputs = np.append(outputs, x)
x = 4 * x * (1 - x)
outputs = np.append(outputs, x)

plt.plot(inputs, outputs, 'b-', lw=0.2)

# Plot the logistic map function and line y=x.


X = np.linspace(0, 1, 200, endpoint=True)
plt.plot(X, 4 * X * (1 - X), 'k-')
plt.plot(X, X, 'r-')
plt.xlabel('x', fontsize=15)
plt.ylabel('$f_{\mu}(x)$', fontsize=15)
plt.tick_params(labelsize=15)

plt.show()

62 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [71]: # Program 15a: Plot points for the Julia set.


# See Figure 15.1.
from matplotlib import pyplot as plt
import random
from sympy import sqrt,re,im,I

# Parameters
a =0;b=1.1; # To plot J(a,b).
k=15
Num_iterations=2**k

def Julia(X):
x, y = X
x1=x;y1=y;
u = sqrt((x1-a)**2+(y1-b)**2)/2
v=(x-a)/2
u1=sqrt(u+v)
v1=sqrt(u-v)
xn=u1;yn=v1;
if y1<b:
yn=-yn
if random.random() < 0.5:
xn=-u1
yn=-yn
return xn, yn

x1=(re(0.5+sqrt(0.25-(a+b*I)))).expand(complex=True)
y1=(im(0.5+sqrt(0.25-(a+b*I)))).expand(complex=True)
isunstable=2*abs(x1+y1*I)
print(isunstable)

X0 = [x1, y1]
X, Y = [], []
for i in range(Num_iterations):
xn, yn = Julia(X0)
X, Y = X + [xn], Y + [yn]
X0 = [xn, yn]

fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(X, Y, color='blue', s=0.15)
ax.axis('off')
plt.show()

63 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

2.97195366175600

64 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [72]: # Program 15b: Colormap of a Julia set.


# See Figure 15.2.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm # Use a colormap.

# Set image dimensions.


Im_w, Im_h = 500, 500
c = complex(-0.1,0.65) # To plot J(a,b).
Max_abs_z = 10
Max_iter = 1000
xmin, xmax = -2, 2
xrange = xmax - xmin
ymin, ymax = -2, 2
yrange = ymax - ymin

Julia = np.zeros((Im_w, Im_h))


for Re_z in range(Im_w):
for Im_y in range(Im_h):
nit = 0
# Map pixel position to a point in the plane
z = complex(Re_z / Im_w * xrange+ xmin,
Im_y / Im_h * yrange + ymin)
# Do the iterations
while abs(z) <= Max_abs_z and nit < Max_iter:
z = z**2 + c
nit += 1
ratio = nit / Max_iter
Julia[-Im_y,Re_z] = ratio # Set axes to Re(z) and Im(z).

fig, ax = plt.subplots(figsize=(6,6))
ax.axis('off')
ax.imshow(Julia, interpolation='nearest', cmap=cm.hot)
plt.show()

65 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [73]: # Program 15c: The Mandelbrot set.


# See Figure 15.3.

import numpy as np
import matplotlib.pyplot as plt
xmin=-2.5;xmax=1;ymin=-1.5;ymax=1.5;
xrange=xmax-xmin;yrange=ymax-ymin;

def mandelbrot(h,w, Max_it=50):


y,x = np.ogrid[ ymin:ymax:h*1j, xmin:xmax:w*1j ]
c = x+y*1j
z = c
Div_iter = Max_it + np.zeros(z.shape, dtype=int)

for i in range(Max_it):
z = z**2 + c
Div_test = z*np.conj(z) > 2**2
Div_num = Div_test & (Div_iter==Max_it)
Div_iter[Div_num] = i
z[Div_test] = 2

return Div_iter # Number of iterations to diverge.

scale=1000 # Amount of detail in the set.

# Set the tick labels to the Argand plane.


fig, ax = plt.subplots(figsize=(7,7))
ax.imshow(mandelbrot(scale,scale))
xtick_labels = np.linspace(xmin, xmax, xrange / 0.5)
ax.set_xticks([(x-xmin) / xrange * scale for x in xtick_labels])
ax.set_xticklabels(['{:.1f}'.format(xtick) for xtick in xtick_labels])
ytick_labels = np.linspace(ymin, ymax, yrange / 0.5)
ax.set_yticks([-(y+ymin) / yrange * scale for y in ytick_labels])
ax.set_yticklabels(['{:.1f}'.format(ytick) for ytick in ytick_labels])
plt.xlabel("Re(z)",fontsize=15)
plt.ylabel("Im(z)",fontsize=15)
plt.show()

66 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:29: DeprecationWar
ning: object of type <class 'float'> cannot be safely interpreted as an integer
.
/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:32: DeprecationWar
ning: object of type <class 'float'> cannot be safely interpreted as an integer
.

67 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [74]: # Program 15d: The Newton fractal for f(z)=z**3-1.


# Newton-Rapshon method.
# See Figure 15.7 (alternative form to book).

from PIL import Image


import numpy as np

epsilon, scale, niters = 0.0001, 600, 40


xmin, xmax = -1.5, 1.5
ymin, ymax = -1.5, 1.5

# Create blank image.


img=Image.new("RGB", (scale, scale), (0, 0, 0))

# Roots of z**3-1 = 0 (Euler's formula).


roots = [np.cos((2*n)*np.pi/3)+1j*np.sin((2*n)*np.pi/3) for n in range(3)]
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] # RGB.

for re in range(scale):
zx=re*(xmax-xmin)/(scale-1)+xmin
for im in range(scale):
zy=im*(ymax-ymin)/(scale-1)+ymin
z=complex(zx, zy)
for i in range(niters):
try:
z -= (z**3-1)/(3*z**2)
except ZeroDivisionError:
# Divide by zero exception.
continue
if(abs(z**3-1) < epsilon):
break

# Shade colors.
color_shade = int((niters-i)*255.0/niters)

# RGB roots.
err = [ abs(z-root) for root in roots ]
distances = zip(err, range(len(colors)))

# Select color.
color = [i*color_shade for i in colors[min(distances)[1]]]
img.putpixel((re, im), tuple(color))

img.save('Newton_Fractal.png','PNG')
img.show()

68 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [75]: # Program 16a: Intersection of implicit curves.


# See Figure 16.10(b): To find fixed points of period one.

import numpy as np
import matplotlib.pyplot as plt

A, B = 2.2, 0.15

x, y = np.mgrid[0:4:100j, -4:4:100j]
z1 = A + B*x*np.cos(x**2 + y**2) - B*y*np.sin(x**2 + y**2) - x
z2 = B*x*np.sin(x**2 + y**2) + B*y*np.cos(x**2 + y**2) - y

fig, ax = plt.subplots()
plt.contour(x, y, z1, levels=[0])
plt.contour(x, y, z2, levels=[0], colors='r')
ax.set_xlabel('x(t)', fontsize=15)
ax.set_ylabel('y(t)', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

69 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [76]: # Program 16b: Iteration of the Ikeda map.


# See Figure 16.11(b): Chaotic attractor.

from matplotlib import pyplot as plt


import numpy as np

# Parameters
A, B = 10, 0.15

def ikeda(X):
x, y = X
xn = A + B*x*np.cos(x**2 + y**2) - B*y*np.sin(x**2 + y**2)
yn = B*x*np.sin(x**2 + y**2) + B*y*np.cos(x**2 + y**2)
return (xn, yn)

X0 = [A, 0]
X, Y = [], []
for i in range(10000):
xn, yn = ikeda(X0)
X, Y = X + [xn], Y + [yn]
X0 = [xn, yn]

fig, ax = plt.subplots(figsize=(6,6))
ax.scatter(X, Y, color='blue', s=0.1)
plt.xlabel('$Re(E_n)$', fontsize=15)
plt.ylabel('$Im(E_n)$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

70 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [77]: # Program 16c: Bifurcation diagram of the Ikeda map.


# See Figure 16.16(d). Instabilities encroach on hysteresis.

from matplotlib import pyplot as plt


import numpy as np

# Parameters
C = 0.345913
kappa = 0.0225
Pmax = 120
phi = np.pi
half_N = 4999
N = 2*half_N + 1
N1 = 1 + half_N
esqr_up, esqr_down = [], []
E1 = E2 = 0
ns_up = np.arange(half_N)
ns_down = np.arange(N1, N)

# Ramp the power up


for n in ns_up:
E2 = E1 * np.exp(1j*((abs(C*E1))**2 - phi))
E1 = 1j * np.sqrt(1 - kappa) * np.sqrt(n * Pmax / N1) + \
np.sqrt(kappa) * E2
esqr1 = abs(E1)**2
esqr_up.append([n, esqr1])

esqr_up = np.array(esqr_up)

# Ramp the power down


for n in ns_down:
E2 = E1 * np.exp(1j * ((abs(C*E1))**2 - phi))
E1 = 1j * np.sqrt(1 - kappa) * np.sqrt(2 * Pmax - n * Pmax / N1) \
+ np.sqrt(kappa) * E2
esqr1 = abs(E1)**2
esqr_down.append([N-n, esqr1])

esqr_down=np.array(esqr_down)

fig, ax = plt.subplots()
xtick_labels = np.linspace(0, Pmax, 6)
ax.set_xticks([x / Pmax * N1 for x in xtick_labels])
ax.set_xticklabels(['{:.1f}'.format(xtick) for xtick in xtick_labels])

plt.plot(esqr_up[:, 0], esqr_up[:, 1], 'r.', markersize=0.1)


plt.plot(esqr_down[:, 0], esqr_down[:, 1], 'b.', markersize=0.1)
plt.xlabel('Input', fontsize=15)
plt.ylabel('Output', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

71 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

72 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [78]: # Programs 17a: Plotting the Koch curve.


# See Figure 17.2.

import numpy as np
import matplotlib.pyplot as plt
from math import floor

k=6
n_lines = 4**k
h = 3**(-k);
x = [0]*(n_lines+1)
y = [0]*(n_lines+1)
x[0], y[0] = 0, 0

segment=[0] * n_lines;

# The angles of the four segments.


angle=[0, np.pi/3, -np.pi/3, 0]
for i in range(n_lines):
m=i
ang=0
for j in range(k):
segment[j] = np.mod(m, 4)
m = floor(m / 4)
ang = ang + angle[segment[j]]

x[i+1] = x[i] + h*np.cos(ang)


y[i+1] = y[i] + h*np.sin(ang)

plt.axis('equal')
plt.plot(x,y)
plt.show()

73 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [79]: # Program 17b: The chaos game and Sierpinski triangle.


# See Figure 17.6.

import matplotlib.pyplot as plt


from random import random, randint
import numpy as np

def midpoint(P, Q):


return (0.5*(P[0] + Q[0]), 0.5*(P[1] + Q[1]))

# The three vertices.


vertices = [(0, 0), (2, 2*np.sqrt(3)), (4, 0)]

iterates = 50000
x, y = [0]*iterates, [0]*iterates
x[0], y[0] = random(), random()

for i in range(1, iterates):


k = randint(0, 2)
x[i], y[i] = midpoint(vertices[k], (x[i-1], y[i-1]))

fig, ax = plt.subplots(figsize=(6, 6))


ax.scatter(x, y, color='r', s=0.1)
ax.axis('off')
plt.show()

74 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [80]: # Program 17c: Barnsley's fern.


# See Figure 17.7.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm

# The transformation T
f1 = lambda x, y: (0.0, 0.2*y)
f2 = lambda x, y: (0.85*x + 0.05*y, -0.04*x + 0.85*y + 1.6)
f3 = lambda x, y: (0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6)
f4 = lambda x, y: (-0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44)
fs = [f1, f2, f3, f4]

num_points = 60000

width = height = 300


fern = np.zeros((width, height))

x, y = 0, 0
for i in range(num_points):
# Choose a random transformation
f = np.random.choice(fs, p=[0.01, 0.85, 0.07, 0.07])
x, y = f(x,y)
# Map (x,y) to pixel coordinates
# Center the image
cx, cy = int(width / 2 + x * width / 10), int(y * height / 10)
fern[cy, cx] = 1

fig, ax=plt.subplots(figsize=(6,6))
plt.imshow(fern[::-1,:], cmap=cm.Greens)
ax.axis('off')
plt.show()

75 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [81]: # Program 17d: Plot tau curve, D_q curve and f(alpha) curve.
# See Figure 17.16: Multifractal spectra.

import numpy as np
import matplotlib.pyplot as plt
import scipy.misc

plt.subplots_adjust(hspace=1)
plt.figure(1)

# The tau curve


x = np.linspace(-20, 20, 1000)
y = (np.log((1/9)**x + (8/9)**x) / np.log(3))

plt.subplot(3, 1, 1)
plt.plot(x, y)
plt.xlabel('$q$', fontsize=15)
plt.ylabel(r'$\tau(q)$', fontsize=15)
plt.tick_params(labelsize=15)

# The D_q curve


x1 = np.linspace(-20, 0.99, 100)
x2 = np.linspace(0.99, 20, 100)
Dq1 = (np.log((1/9)**x1 + (8/9)**x1) / (np.log(3) * (1 - x1)))
Dq2 = (np.log((1/9)**x2 + (8/9)**x2) / (np.log(3) * (1 - x2)))
plt.subplot(3, 1, 2)
plt.plot(x1, Dq1, x2, Dq2)
plt.xlabel('q', fontsize=15)
plt.ylabel('$D_q$', fontsize=15)
plt.tick_params(labelsize=15)

# The f(alpha) curve


p1, p2 = 1/9, 8/9
k = 500
s = np.arange(500)
x = (s*np.log(p1) + (k-s) * np.log(p2)) / (k*np.log(1/3))
f = -(np.log(scipy.special.comb(k, s))) / (k*np.log(1/3))

plt.subplot(3, 1, 3)
plt.plot(x, f)
plt.xlabel(r'$\alpha$', fontsize=15)
plt.ylabel(r'$f(\alpha)$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

76 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [82]: # Program 18a: Generating a multifractal image.


# Save the image.
# See Figure 18.1(b).

import numpy as np
import matplotlib.pyplot as plt
from skimage import exposure, io, img_as_uint

p1, p2, p3, p4 = 0.3, 0.4, 0.25, 0.05


p = [[p1, p2], [p3, p4]]
for k in range(1, 9, 1):
M = np.zeros([2 ** (k + 1), 2 ** (k + 1)])
M.tolist()
for i in range(2**k):
for j in range(2**k):
M[i][j] = p1 * p[i][j]
M[i][j + 2**k] = p2 * p[i][j]
M[i + 2**k][j] = p3 * p[i][j]
M[i + 2**k][j + 2**k] = p4 * p[i][j]
p = M

# Plot the multifractal image.


M = exposure.adjust_gamma(M, 0.2)
plt.imshow(M, cmap='gray', interpolation='nearest')

# Save the image as a portable network graphics (png) image.


im = np.array(M, dtype='float64')
im = exposure.rescale_intensity(im, out_range='float')
im = img_as_uint(im)
io.imsave('Multifractal.png', im)
io.show()

/anaconda3/lib/python3.7/site-packages/skimage/util/dtype.py:141: UserWarning:
Possible precision loss when converting from float64 to uint16
.format(dtypeobj_in, dtypeobj_out))

77 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [83]: # Programs 18d: Counting white pixels in color picture of a raccoon.


# See Figure 18.2.

from scipy import misc


import matplotlib.pyplot as plt
import numpy as np

face = misc.face()

fig1 = plt.figure()
plt.imshow(face)
width, height, _ = face.shape

print('Image dimensions: {}x{}'.format(width, height))


white_pixels = np.zeros((width, height))

def white_pixel_filter(pixel, threshold):


return 1 if all(value > threshold for value in pixel) else 0

for i, row in enumerate(face):


for j, pixel in enumerate(row):
white_pixels[i, j] = white_pixel_filter(pixel, threshold=180)

fig2 = plt.figure()
plt.imshow(white_pixels, cmap='gray')
print('There are {:,} white pixels'.format(int(np.sum(white_pixels))))
plt.show()

Image dimensions: 768x1024


There are 61,253 white pixels

78 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [84]: # Program 18c: Statistical Analysis on Microbes.png.


# See Figures 18.3 and 18.4.

import matplotlib.pyplot as plt


from skimage import io
import numpy as np
from skimage.measure import regionprops
from scipy import ndimage
from skimage import feature

microbes_img = io.imread('Microbes.png')
fig1 = plt.figure()
plt.imshow(microbes_img,cmap='gray', interpolation='nearest')
width, height, _ = microbes_img.shape
binary = np.zeros((width, height))

for i, row in enumerate(microbes_img):


for j, pixel in enumerate(row):
if pixel[0] > 80:
binary[i, j] = 1

fig2 = plt.figure()
plt.imshow(binary,cmap='gray')
print('There are {:,} white pixels'.format(int(np.sum(binary))))

blobs = np.where(binary>0.5, 1, 0)
labels, no_objects = ndimage.label(blobs)
props = regionprops(blobs)
print('There are {:,} clusters of cells:'.format(no_objects))

fig3 = plt.figure()
edges=feature.canny(binary,sigma=2,low_threshold=0.5)
plt.imshow(edges,cmap=plt.cm.gray)

fig4 = plt.figure()
labeled_areas = np.bincount(labels.ravel())[1:]
print(labeled_areas)
plt.hist(labeled_areas,bins=no_objects)
plt.xlabel('Area',fontsize=15)
plt.ylabel('Number of clusters',fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

79 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

There are 38,895 white pixels


There are 106 clusters of cells:
[ 73 15 147 255 885 650 197 1065 228 92 99 92 90 39
91 877 691 502 173 366 1081 44 2417 17 225 109 118 75
174 282 632 45 472 289 128 129 13 375 218 97 1159 284
1560 324 1341 346 532 206 114 377 3264 161 263 187 94 133
221 136 214 161 1065 104 92 289 81 92 54 916 451 444
177 1594 1073 179 158 106 181 365 867 838 44 417 336 77
308 383 194 157 48 26 71 180 22 93 218 1024 97 270
181 66 241 50 221 239 62 100]

80 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

81 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [85]: # Program 18d: Fast Fourier transform (FFT) of a noisy signal.


# See Figure 18.5.

import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft

Ns = 1000 # Number of sampling points


Fs = 800 # Sampling frequency
T = 1/Fs # Sample time
t = np.linspace(0, Ns*T, Ns)
amp1, amp2 = 0.7, 1
freq1, freq2 = 50, 120

# Sum a 50Hz and 120 Hz sinusoid


x = amp1 * np.sin(2*np.pi * freq1*t) + amp2*np.sin(2*np.pi * freq2*t)
y = x + 0.5*np.random.randn(Ns)
fig1 = plt.figure()
plt.plot(t, y)
plt.xlabel('Time (ms)', fontsize=15)
plt.ylabel('y(t)', fontsize=15)
plt.tick_params(labelsize=15)

fig2 = plt.figure()
yf = fft(y)
xf = np.linspace(0, 1/(2*T), Ns//2)
plt.plot(xf, 2/Ns * np.abs(yf[0:Ns//2]))
plt.xlabel('Frequency (Hz)', fontsize=15)
plt.ylabel('$|Y(f)|$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

82 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

83 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [86]: # Program 18e: Iterative map and power spectra.


# See Figure 18.6.

import matplotlib.pyplot as plt


from scipy.fftpack import fft
import numpy as np

# Parameters
a, b = 1, 0.3 # To get Figures 18.6(e) and (f)
n = 50000

def map_2d(X):
x, y = X
xn = 1 - a*y**2 + b*x
yn = x
return (xn, yn)

X0 = [(1 - b) / 2, (1 - b) / 2]
X, Y = [], []
for i in range(n):
xn, yn = map_2d(X0)
X, Y = X + [xn], Y + [yn]
X0 = [xn, yn]

fig, ax = plt.subplots(figsize=(6, 6))


ax.scatter(X, Y, color='blue', s=0.05)
plt.xlabel('x', fontsize=15)
plt.ylabel('y', fontsize=15)
plt.tick_params(labelsize=15)

fig2 = plt.figure()
f = np.linspace(-1, 1, n)
power = np.abs(fft(X)**2)
power = np.log(power)
plt.plot(f, power)
plt.xlim(0, 1)
plt.xlabel('Frequency (Hz)', fontsize=15)
plt.ylabel('log(Power)', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

84 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

85 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [87]: # Program 18f: Fourier transform of a Lena image.


# See Figure 18.7.

import numpy as np
import skimage.io as io
import pylab
import matplotlib.pyplot as plt
from skimage.color import rgb2gray

lena = rgb2gray(io.imread('lena.jpg'))

fig1 = plt.figure()
plt.imshow(lena, cmap='gray')

fig2 = plt.figure()
# Take the 2-dimensional DFT and centre the frequencies
ftimage = np.fft.fft2(lena)
ftimage = np.fft.fftshift(ftimage)
ftimage = np.abs(ftimage)
fftimage = np.log(ftimage)
fftimage = rgb2gray(fftimage)
pylab.imshow(fftimage, cmap='gray')
plt.show()

86 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [88]: # Program 18g: Edge detection on Lena image.


# See Figure 18.8.

import matplotlib.pyplot as plt


import skimage.io as io
from skimage.filters import roberts, sobel
from skimage.color import rgb2gray

lena = rgb2gray(io.imread('lena.jpg'))

edge_roberts = roberts(lena)
edge_sobel = sobel(lena)

fig, ax = plt.subplots(ncols=2, sharex=True, sharey=True, figsize=(8, 4))

ax[0].imshow(edge_roberts, cmap=plt.cm.gray)
ax[0].set_title('Roberts Edge Detection')

ax[1].imshow(edge_sobel, cmap=plt.cm.gray)
ax[1].set_title('Sobel Edge Detection')

for a in ax:
a.axis('off')

plt.tight_layout()
plt.show()

87 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [89]: # Program 19a: Chaos control in the logistic map.


# Control to period two.
# See Figure 19.3(b).

import matplotlib.pyplot as plt


import numpy as np

# Parameters
mu = 4
k = 0.217
num_iterations = 60
xs, x = [], [0.6]
ns = np.arange(0, num_iterations, 2)
nsc = np.arange(num_iterations, 2*num_iterations, 2)

for n in ns:
x1 = mu*x[n] * (1 - x[n])
x.append(x1)
xs.append([n, x1])
x2 = mu*x1 * (1 - x1)
x.append(x2)
xs.append([n+1, x2])

for n in nsc:
x1 = k*mu*x[n] * (1 - x[n])
x.append(x1)
xs.append([n, x1])
x2 = mu*x1 * (1 - x1)
x.append(x2)
xs.append([n+1, x2])

xs = np.array(xs)

fig, ax = plt.subplots(figsize=(6, 6))


plt.plot(xs[:, 0], xs[:, 1])
plt.plot(xs[:, 0], xs[:, 1], 'ro')
plt.xlabel('n', fontsize=15)
plt.ylabel(r'$x_n$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

88 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

89 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [90]: # Program 19b: Chaos control in the Henon Map.


# See Figure 19.6: Control to period one.

import matplotlib.pyplot as plt


import numpy as np
# Parameters
a, b = 1.2, 0.4
xstar = ystar = 0.8358
k1, k2 = -1.8, 1.2
num_iterations = 199
rs = []
x, y = 0.5, 0.6

ns = np.arange(num_iterations)
nsc = np.arange(num_iterations, 2*num_iterations)

for n in ns:
xn = a + b*y - x**2
yn = x
x, y = xn, yn
r = np.sqrt(x**2 + y**2)
rs.append([n, r])

# Check point is in control region


print(x, y)

for n in nsc:
xn = -k1 * (x - xstar) - k2 * (y - ystar) + a + b*y - x**2
yn = x
x, y = xn, yn
r = np.sqrt(x**2 + y**2)
rs.append([n, r])

rs = np.array(rs)

fig, ax = plt.subplots(figsize=(6,6))
plt.plot(rs[:, 0], rs[:, 1])
plt.plot(rs[:, 0], rs[:, 1], 'ro')
plt.xlabel('n', fontsize=15)
plt.ylabel(r'$r_n^2$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

90 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

1.376306895063647 0.41076041951050035

91 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [91]: # Program 19c: Synchronization between two Lorenz systems.


# See Figure 19.7(b).

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Constants
sigma = 16
b = 4
r = 45.92
tmax = 100

t = np.arange(0.0, tmax, 0.1)

def two_lorenz_odes(X, t):


x1, x2, x3, y2, y3 = X
dx1 = sigma * (x2 - x1)
dx2 = -x1 * x3 + r*x1 - x2
dx3 = x1 * x2 - b*x3
dy2 = -x1 * y3 + r*x1 - y2
dy3 = x1 * y2 - b*y3
return (dx1, dx2, dx3, dy2, dy3)

y0 = [15, 20, 30, 10, 20]


X = odeint(two_lorenz_odes, y0, t, rtol=1e-6)
x1, x2, x3, y2, y3 = X.T # unpack columns

plt.figure(1)

plt.plot(x3, y3)
plt.xlabel(r'$x_3$', fontsize=15)
plt.ylabel(r'$y_3$', fontsize=15)
plt.show()

92 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [92]: # Program 19d: Generalized synchronization.


# See Figure 19.8(a).

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Constants
mu = 5.7
sigma = 16
b = 4
r = 45.92
g = 8 # When g=4, there is no synchronization.
tmax = 100

t = np.arange(0.0, tmax, 0.1)

def rossler_lorenz_odes(X,t):
x1, x2, x3, y1, y2, y3, z1, z2, z3 = X
dx1 = -(x2 + x3)
dx2 = x1 + 0.2*x2
dx3 = 0.2 + x3 * (x1 - mu)
dy1 = sigma * (y2 - y1) - g * (y1 - x1)
dy2 = -y1 * y3 + r*y1 - y2
dy3 = y1 * y2 - b*y3
dz1 = sigma * (z2 - z1) - g * (z1 - x1)
dz2 = -z1*z3 + r*z1 - z2
dz3 = z1*z2 - b*z3
return (dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3)

y0 = [2, -10, 44, 30, 10, 20, 31, 11, 22]


X = odeint(rossler_lorenz_odes, y0, t, rtol=1e-6)
x1, x2, x3, y1, y2, y3, x1, z2, z3 = X.T # unpack columns

plt.figure(1)
# Delete first 500 iterates.
plt.plot(y2[500:len(y2)], z2[500:len(z2)])
plt.xlabel(r'$y_2$', fontsize=15)
plt.ylabel(r'$z_2$', fontsize=15)
plt.show()

93 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [93]: # Program 20a: The generalized delta learning rule.


# Backpropagation of errors - using the perceptron.
# Training Boston housing data (housing.txt).
# The target is the value of a house (column 13).
# In this case, use 3 attributes (columns 5, 8, and 12).
# See figure 20.7.

import matplotlib.pyplot as plt


import numpy as np

data = np.loadtxt('housing.txt')
rows, columns = data.shape
columns = 4 # Using 4 columns from data in this case

X = data[:, [5, 8, 12]]


t = data[:, 13]
ws1, ws2, ws3, ws4 = [], [], [], []
k = 0

xmean = X.mean(axis=0)
xstd = X.std(axis=0)
ones = np.array([np.ones(rows)])
X = (X - xmean * ones.T) / (xstd * ones.T)
X = np.c_[np.ones(rows), X]

tmean = (max(t) + min(t)) / 2


tstd = (max(t) - min(t)) / 2
t = (t - tmean) / tstd

w = 0.1 * np.random.random(columns)
y1 = np.tanh(X.dot(w))
e1 = t - y1
mse = np.var(e1)

num_epochs = 10 # number of iterations


eta = 0.001
k = 1

for m in range(num_epochs):
for n in range(rows):
yk = np.tanh(X[n, :].dot(w))
err = yk - t[n]
g = X[n, :].T * ((1 - yk**2) * err)
w = w - eta*g
k += 1
ws1.append([k, np.array(w[0]).tolist()])
ws2.append([k, np.array(w[1]).tolist()])
ws3.append([k, np.array(w[2]).tolist()])
ws4.append([k, np.array(w[3]).tolist()])

ws1 = np.array(ws1)
ws2 = np.array(ws2)
ws3 = np.array(ws3)
ws4 = np.array(ws4)

plt.plot(ws1[:, 0], ws1[:, 1], 'k.', markersize=0.1)


plt.plot(ws2[:, 0], ws2[:, 1], 'g.', markersize=0.1)
plt.plot(ws3[:, 0], ws3[:, 1], 'b.', markersize=0.1)
plt.plot(ws4[:, 0], ws4[:, 1], 'r.', markersize=0.1)
plt.xlabel('Number of iterations', fontsize=15)
plt.ylabel('Weights', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

94 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [94]: # Program 20b: The discrete Hopfield network.


# See Example 5.

from sympy import Matrix, eye


import random

# The fundamental memories:


x1 = [1, 1, 1, 1, 1]
x2 = [1, -1, -1, 1, -1]
x3 = [-1, 1, -1, 1, 1]

X = Matrix([x1, x2, x3])


W = X.T * X / 5 - 3*eye(5) / 5

def hsgn(v, x):


if v > 0:
return 1
elif v == 0:
return x
else:
return -1

L = [0, 1, 2, 3, 4]
n = random.sample(L, len(L))

xinput = [1, -1, -1, 1, 1]


xtest = xinput
for j in range(4):
M = W.row(n[j]) * Matrix(xtest)
xtest[n[j]] = hsgn(M[0], xtest[n[j]])

if xtest == x1:
print('Net has converged to X1')
elif xtest == x2:
print('Net has converged to X2')
elif xtest == x3:
print('Net has converged to X3')
else:
print('Iterate again: May have converged to spurious state')

Net has converged to X1

95 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [95]: # Program 20c: Iteration of the minimal chaotic neuromodule.


# See Figure 20.13: Chaotic attractor.

import matplotlib.pyplot as plt


import numpy as np

# Parameters
b1, b2, w11, w21, w12, a = -2, 3, -20, -6, 6, 1
num_iterations = 10000

def neuromodule(X):
x,y=X
xn=b1+w11/(1+np.exp(-a*x))+w12/(1+np.exp(-a*y))
yn=b2+w21/(1+np.exp(-a*x))
return xn,yn

X0 = [0, 2]
X, Y = [], []

for i in range(num_iterations):
xn, yn = neuromodule(X0)
X, Y = X + [xn], Y + [yn]
X0 = [xn, yn]

fig, ax = plt.subplots(figsize=(6, 6))


ax.scatter(X, Y, color='blue', s=0.1)
plt.xlabel('x', fontsize=15)
plt.ylabel('y', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

96 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [96]: # Program 20d: Bifurcation diagram of the neuromodule.


# See Figure 20.15: Hysteresis in a neuromodule.

from matplotlib import pyplot as plt


import numpy as np

# Parameters
b2, w11, w21, w12, a = 3, 7, 5, -4, 1
start, max = -5, 10
half_N = 1999
N = 2 * half_N + 1
N1 = 1 + half_N
xs_up, xs_down = [], []
x, y = -10, -3
ns_up = np.arange(half_N)
ns_down = np.arange(N1, N)

# Ramp b1 up
for n in ns_up:
b1 = start + n*max / half_N
x = b1 + w11 / (1 + np.exp(-a*x)) + w12 / (1 + np.exp(-a*y))
y = b2+w21 / (1 + np.exp(-a*x))
xn = x
xs_up.append([n, xn])
xs_up = np.array(xs_up)

# Ramp b1 down
for n in ns_down:
b1 = start + 2*max - n*max / half_N
x = b1 + w11 / (1 + np.exp(-a*x)) + w12 / (1 + np.exp(-a*y))
y = b2 + w21 / (1 + np.exp(-a*x))
xn = x
xs_down.append([N-n, xn])
xs_down = np.array(xs_down)

fig, ax = plt.subplots()
xtick_labels = np.linspace(start, max, 7)
ax.set_xticks([(-start + x) / max * N1 for x in xtick_labels])
ax.set_xticklabels(['{:.1f}'.format(xtick) for xtick in xtick_labels])

plt.plot(xs_up[:, 0], xs_up[:, 1], 'r.', markersize=0.1)


plt.plot(xs_down[:, 0], xs_down[:,1], 'b.', markersize=0.1)
plt.xlabel(r'$b_1$', fontsize=15)
plt.ylabel(r'$x_n$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

97 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

98 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [97]: # Program 21a: The Hodgkin-Huxley Equations.


# See Figures 21.2 and 21.3.

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Constants
C_m = 1.0 # uF/cm^2
g_Na = 120.0 # mS/cm^2
g_K = 36.0
g_L = 0.3
V_Na = 50.0 # mV
V_K = -77.0
V_L = -54.402

# See equations (21.4)


def alpha_m(V): return 0.1 * (V + 40.0) / (1.0 - np.exp(-0.1 * (V + 40.0)))
def beta_m(V): return 4.0 * np.exp(-0.0556 * (V + 65.0))
def alpha_h(V): return 0.07 * np.exp(-0.05 * (V + 65.0))
def beta_h(V): return 1.0 / (1.0 + np.exp(-0.1 * (V + 35.0)))
def alpha_n(V): return 0.01 * (V + 55.0) / (1.0 - np.exp(-0.1 * (V + 55.0)))
def beta_n(V): return 0.125 * np.exp(-0.0125 * (V + 65))

# See equation (21.2)


def I_Na(V,m,h): return g_Na * m**3 * h * (V - V_Na)
def I_K(V, n): return g_K * n**4 * (V - V_K)
def I_L(V): return g_L * (V - V_L)

# Input current
def Input_current(t): return 10 * (t > 100) - 10 * (t > 200) + 25 * (t > 300)

t = np.arange(0.0, 400.0, 0.1)

# Set up the ODEs, see equations (21.3)


def hodgkin_huxley(X, t):
V, m, h, n = X
dVdt = (Input_current(t) - I_Na(V, m, h) - I_K(V, n) - I_L(V)) / C_m
dmdt = alpha_m(V) * (1.0 - m) - beta_m(V) * m
dhdt = alpha_h(V) * (1.0 - h) - beta_h(V) * h
dndt = alpha_n(V) * (1.0 - n) - beta_n(V) * n
return (dVdt, dmdt, dhdt, dndt)

y0 = [-65, 0.05, 0.6, 0.32]


X = odeint(hodgkin_huxley, y0, t)
V = X[:, 0]
m = X[:, 1]
h = X[:, 2]
n = X[:, 3]
ina = I_Na(V, m, h)
ik = I_K(V, n)
il = I_L(V)

plt.subplots_adjust(hspace = 1)
plt.figure(1)

plt.subplot(5, 1, 1)
plt.title('Hodgkin-Huxley Neuron')
plt.plot(t, V, 'b')
plt.ylabel('V (mV)')

plt.subplot(5, 1, 2)
plt.plot(t m 'k')

99 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

100 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [98]: # Program 21b: The Fitzhugh-Nagumo Half-Adder.


# See Figure 21.6.

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Input current.
def Input_1(t):
return 1*(t>500)-1*(t>1000)+1*(t>1500)
def Input_2(t):
return 1*(t>1000)

# Constants
theta=0.1;gamma=0.1;epsilon=0.1;
Tmax=2000;
m=-100;c=60;

t=np.arange(0.0, 2000.0, 0.1)

def FN_ODEs(X,t):
u1,v1,u2,v2,u3,v3,u4,v4=X
du1 = -u1*(u1-theta)*(u1-1)-v1+Input_1(t)
dv1 = epsilon*(u1-gamma*v1)
du2 = -u2*(u2-theta)*(u2-1)-v2+Input_2(t)
dv2 = epsilon*(u2-gamma*v2)
du3 = -u3*(u3-theta)*(u3-1)-v3+0.8/(1+np.exp(m*v1+c))+ \
0.8/(1+np.exp(m*v2+c))-1.5/(1+np.exp(m*v4+c))
dv3 = epsilon*(u3-gamma*v3)
du4 = -u4*(u4-theta)*(u4-1)-v4+0.45/(1+np.exp(m*v1+c))+ \
0.45/(1+np.exp(m*v2+c))
dv4 = epsilon*(u4-gamma*v4)
return du1,dv1,du2,dv2,du3,dv3,du4,dv4

X = odeint(FN_ODEs,[0.01,0.01,0.01,0.01,0,0,0,0],t,rtol=1e-6)
u1 = X[:,0];v1 = X[:,1];u2 = X[:,2];v2 = X[:,3]
u3 = X[:,4];v3 = X[:,5];u4 = X[:,6];v4 = X[:,7]

plt.subplots_adjust(hspace = 1)
plt.figure(1)

plt.subplot(4,1,1)
plt.title('Fitzhugh-Nagumo Half-Adder')
plt.plot(t, u1, 'b')
plt.ylim(-1, 1.5)
plt.ylabel('I$_1$')

plt.subplot(4,1,2)
plt.plot(t, u2, 'b')
plt.ylim(-1, 1.5)
plt.ylabel('I$_2$')

plt.subplot(4,1,3)
plt.plot(t, u3, 'g')
plt.ylim(0, 1)
plt.ylim(-1, 1.5)
plt.ylabel('O$_1$')

plt.subplot(4,1,4)
plt.plot(t, u4, 'g')
plt.ylim(-1, 1.5)
plt.ylabel('O$_2$')

101 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [99]: # Program 21c: Josephson junction (JJ) limit cycle.


# See Figure 21.9.

from matplotlib import pyplot as plt


import numpy as np
from scipy.integrate import odeint

fig = plt.figure()

bj = 1.2
tmax = 100
kappa = 1.4

def jj_ode(x, t):


return [x[1], kappa - bj*x[1] - np.sin(x[0])]

time = np.arange(0, tmax, 0.1)


x0=[0.1,0.1]
xs = odeint(jj_ode, x0, time)
imgplot = plt.plot(np.sin(xs[:, 0]), xs[:, 1], 'r-')

plt.xlabel(r'$\sin(\phi)$', fontsize=15)
plt.ylabel(r'$\Omega$', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

102 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [ ]: # Program 21d: Animation of a JJ limit cycle bifurcation.


# These are threshold oscillators, much like biological neurons.
# They oscillate one hundred million times faster than neurons!
# See Figure 21.9.

from matplotlib import pyplot as plt


from matplotlib.animation import ArtistAnimation
import numpy as np
from scipy.integrate import odeint

fig = plt.figure()
myimages = []

bj = 1.2
tmax = 100

def jj_ode(x, t):


return [x[1], kappa - bj*x[1] - np.sin(x[0])]

time = np.arange(0, tmax, 0.1)


x0 = [0.1, 0.1]
for kappa in np.arange(0.1, 2, 0.1):
xs = odeint(jj_ode, x0, time)
imgplot = plt.plot(np.sin(xs[:, 0]), xs[:, 1], 'r-')
myimages.append(imgplot)

my_anim = ArtistAnimation(fig, myimages, interval=100, blit=False, repeat_delay


=100)
plt.show()

103 of 104 3/31/19, 3:03 PM


Dynamical_Systems_with_Applications_using_Python http://www.doc.mmu.ac.uk/STAFF/S.Lynch/DSAP...

In [100]: # Program 21e: Pinched hysteresis in a memristor.


# See Figure 21.12.

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Constants
eta, L, Roff, Ron, p, T, w0 = 1.0, 1.0, 70.0, 1.0, 10.0, 20.0, 0.5

t=np.arange(0.0, 40.0, 0.01)

# Set up the ODEs, see equations (21.3)


def memristor(X, t):
w = X
dwdt = ((eta * (1 - (2*w - 1) ** (2*p)) * np.sin(2*np.pi * t/T))
/ (Roff - (Roff - Ron) * w))
return dwdt

X = odeint(memristor, [w0], t, rtol=1e-12)


w = X[:, 0]

plt.plot(np.sin(2*np.pi * t/T), np.sin(2*np.pi * t/T)


/ (Roff - (Roff - Ron) * X[:, 0]), 'b')
plt.xlabel('voltage', fontsize=15)
plt.ylabel('current', fontsize=15)
plt.tick_params(labelsize=15)
plt.show()

DYNAMICAL SYSTEMS WITH APPLICATIONS USING PYTHON


Copyright: Springer International Publishing, 2018
Dr Stephen Lynch FIMA SFHEA
THE END!

104 of 104 3/31/19, 3:03 PM

You might also like