Consider an object with mass $m$ on a 2D space sliding freely on a curve $y = h(x)$. Here $h(x)$ gives the height at horizontal coordinate $x$. As the object will be constraint to the curve, it will always be at some coordinate $(x, h(x))$ so we will refer to its position by $x$.
Remember from high school physics that under constant gravity $g$ with velocity $v$ the object has
Under energy preservation we have $$ H_{\text{total}} = U + K = m g h(x) + \frac{1}{2m} p^2 $$
As $m$ and $g$ are constants, we can define any motion as some trajectory in the $x,p$ coordinate plane as a function of time. Hamiltonian dynamics is the description of this idea in a more general setting for some arbitrary potential function $U$ and kinetic energy $K$.
We define position variables $x$, a potential function $U(x)$, momentum variables $p$ and kinetic energy $K(p)$.
$$ H(x, p) = U(x) + K(p) $$The change of position in time is described by the change in the Kinetic energy $$ \frac{d x_i}{d t} = \frac{\partial H}{\partial p_i} $$
The change in momentum is in the opposite direction of the change in potential energy $$ \frac{d p_i}{d t} = -\frac{\partial H}{\partial x_i} $$ We accelerate if we fall down and deccelerate if we jump up (under the gravity field that defines the potential at height $h(x)$).
Example: Take $g=1$ and $m=1$
$$U(x) = \frac{1}{2} x^2$$$$K(p) = \frac{1}{2} p^2 $$$$H(x, p) = \frac{1}{2} x^2 + \frac{1}{2} p^2$$$$ \frac{\partial H}{\partial p} = p $$$$ \frac{\partial H}{\partial x} = x $$Hence
$$ \frac{d x}{d t} = p $$$$ \frac{d p}{d t} = -x $$
In [2]:
%matplotlib inline
import scipy as sc
import numpy as np
import scipy.linalg as la
import matplotlib.pyplot as plt
A = np.mat('[0,1;-1,0]')
dt = 0.05
T = 100
z = np.mat(np.zeros((2,T)))
H = la.expm(dt*A)
z[:,0] = np.mat('[2.4;0]')
for i in range(1,T):
z[:,i] = H*z[:,i-1]
plt.plot(z[0,:], z[1,:],'.-r')
ax = plt.gcf().gca()
ax.set_aspect('equal')
plt.show()
Position Evolution \begin{eqnarray} \frac{x_i(t + \epsilon) - x_i(t)}{\epsilon} & = & \frac{d x_i}{d t}(t) = \frac{\partial K}{\partial p_i}(p_i(t)) \\ x_i(t + \epsilon) & = & x_i(t) + \epsilon \frac{\partial K}{\partial p_i}(p_i(t)) \end{eqnarray}
Momentum Evolution \begin{eqnarray} \frac{p_i(t + \epsilon) - p_i(t)}{\epsilon} & = & \frac{d p_i}{d t}(t) = - \frac{\partial U}{\partial x_i}(x_i(t)) \\ p_i(t + \epsilon) & = & p_i(t) - \epsilon \frac{\partial U}{\partial x_i}(x_i(t)) \\ \end{eqnarray}
In [3]:
epsilon = 0.05
T = 1000
z_euler = np.mat(np.zeros((2,T)))
def dHdx(x):
return x
def dHdp(p):
return p
z_euler[:,0] = np.mat('[2.4;0]')
for i in range(1,T):
#z_euler[:,i] = z_euler[:,i-1] + epsilon*dH(z_euler[:,i-1])
z_euler[0,i] = z_euler[0,i-1] + epsilon*dHdp(z_euler[1,i-1])
z_euler[1,i] = z_euler[1,i-1] - epsilon*dHdx(z_euler[0,i-1])
plt.plot(z_euler[0,:], z_euler[1,:],'.-r')
ax = plt.gcf().gca()
ax.set_aspect('equal')
plt.show()
In [4]:
epsilon = 0.01
T = 600
z_euler2 = np.mat(np.zeros((2,T)))
def dHdx(x):
return x
def dHdp(p):
return p
z_euler2[:,0] = np.mat('[2.4;0]')
for i in range(1,T):
z_euler2[0,i] = z_euler2[0,i-1] + epsilon*dHdp(z_euler2[1,i-1])
z_euler2[1,i] = z_euler2[1,i-1] - epsilon*dHdx(z_euler2[0,i])
plt.plot(z_euler2[0,:], z_euler2[1,:],'.-r')
ax = plt.gcf().gca()
ax.set_aspect('equal')
plt.show()
Approximate the momentum at the middle of the time interval.
\begin{eqnarray} \frac{p_i(t + \epsilon/2) - p_i(t)}{\epsilon/2} & = & \frac{d p_i}{d t}(t) = - \frac{\partial U}{\partial x_i}(x_i(t)) \\ p_i(t + \epsilon/2) & = & p_i(t) - (\epsilon/2) \frac{\partial U}{\partial x_i}(x_i(t)) \end{eqnarray}Use the half-way momentum to approximate the position \begin{eqnarray} \frac{x_i(t + \epsilon) - x_i(t)}{\epsilon} & = & \frac{d x_i}{d t}(t + \epsilon/2) = \frac{\partial K}{\partial p_i}(p_i(t+\epsilon/2)) \\ x_i(t + \epsilon) &=& x_i(t) + \epsilon \frac{\partial K}{\partial p_i}(p_i(t+\epsilon/2)) \end{eqnarray}
Update the momentum at time $t+\epsilon$ \begin{eqnarray} \frac{p_i(t + \epsilon) - p_i(t + \epsilon/2)}{\epsilon/2} & = & \frac{d p_i}{d t}(t+\epsilon) = - \frac{\partial U}{\partial x_i}(x_i(t + \epsilon)) \\ p_i(t + \epsilon) & = & p_i(t+\epsilon/2) - (\epsilon/2) \frac{\partial U}{\partial x_i}(x_i(t+\epsilon)) \end{eqnarray}
In [5]:
epsilon = 0.5
T = 50
def dHdx(x):
return x
def dHdp(p):
return p
#def dHdx(x):
# A = np.mat('[1;-1]')
# b = np.mat('[1;3]')
# u = (b - A*x)
# if np.all(u > 0):
# g = A.T*(1/u)
# else:
# g = np.inf*u
# return g[0,0]
T = 100
z_lf = np.mat(np.zeros((2,T)))
z_lf[:,0] = np.mat('[0.1;0]')
for i in range(1,T):
p_mid = z_lf[1,i-1] - (epsilon/2)*dHdx(z_lf[0,i-1])
z_lf[0,i] = z_lf[0,i-1] + epsilon*dHdp(p_mid)
z_lf[1,i] = p_mid - (epsilon/2)*dHdx(z_lf[0,i])
plt.plot(z_lf[0,:].T, z_lf[1,:].T,'or-')
ax = plt.gcf().gca()
ax.set_aspect('equal')
plt.show()