In [1]:
import quimb as qu
n = 18
H = qu.ham_heis(n, sparse=True).real
psi0 = qu.rand_product_state(n)
We can do a few checks on the system like $\langle \psi | \psi \rangle$:
In [2]:
# check normalization
qu.expectation(psi0, psi0)
Out[2]:
and $\langle \psi | H | \psi \rangle$:
In [3]:
# find the initial energy
qu.expec(H, psi0)
Out[3]:
or $\langle \psi | H^2 | \psi \rangle$:
In [4]:
# find the initial variance in energy
psi0.H @ H @ H @ psi0
Out[4]:
Let's compare this to the total energy spectrum of the Hamiltonian H
:
In [5]:
%%time
en_low, en_high = qu.bound_spectrum(H)
print("Highest energy:", en_high)
print("Lowest energy:", en_low)
From which we can infer that our initial state has roughly has overlap between many states in the centre of the spectrum.
In [6]:
def compute(t, pt):
"""Perform computation at time ``t`` with state ``pt``.
"""
dims = [2] * n
lns = [qu.logneg_subsys(pt, dims, i, i + 1) for i in range(n - 1)]
mis = [qu.mutinf_subsys(pt, dims, i, i + 1) for i in range(n - 1)]
return t, lns, mis
Set up the evolution with the initial state, hamiltonian and the compute dict:
In [7]:
evo = qu.Evolution(psi0, H, compute=compute, progbar=True)
Update the evolution to t=5
. The functions in compute
will be called at each step the integrator uses. If we had set method='solve'
or method='expm'
, we should use the generator evo.at_times(ts)
to specify the time steps when computation takes place.
In [8]:
evo.update_to(5)
We can extract the results of the computation from evo.results
and plot them:
In [9]:
%matplotlib inline
import matplotlib.pyplot as plt
ts, lns, mis = zip(*evo.results)
fig, axs = plt.subplots(2, 1, sharex=True)
axs[0].plot(ts, lns);
axs[0].set_title("Logarithmic Negativity")
axs[1].plot(ts, mis);
axs[1].set_title("Mutual Information")
plt.show()
We can see that the classical correlations outlast the quantum correlations.
Finally, let's check that energy has been conserved in the current state at t=5
:
In [10]:
qu.expec(H, evo.pt)
Out[10]: