Fichier:Hamiltonian flow quantum.webm

Fichier d’origine(Fichier audio/vidéo WebM VP9, durée 31 s, 1 200 × 900 pixels, 3,84 Mb/s sur l’ensemble)

Ce fichier et sa description proviennent de Wikimedia Commons.

Description

Description
English: Long time evolution of a quantum ensemble (mixed state) in an 1D anharmonic potential well, as visualized in phase space by the w:Wigner quasiprobability distribution. Because the potential well is not harmonic, the time-evolution is nontrivial.
Equilibrated (i.e., time-averaged) counterpart to this state.
Evolution of the position-position density matrix that was used to calculate this Wigner function. This contains equal information but represented differently.
  • Marginal probability distributions are shown on the right (probability distribution of momentum), and the top (probability distribution of position).
  • To get an idea of the "quantumness", the values of Planck constant (h) and reduced Planck constant () are also shown as areas in phase space (they have units of momentum * distance, so area is appropriate).
  • The initial evolution is shown for 500 frames (21 seconds), then it jumps forward in time to show typical late-time evolution (after an hour, and after a year).

This is a counterpart to the classical swirling flow in the same potential, seen below.

Hamiltonian flow classical

In the quantum case we have a similar swirling motion, but because of the uncertainty principle, there is a limit to how fine the swirling can become. As a result, all the subtle correlations stay visible forever. So, the way Gibbs explained entropy increase by finer and finer mixing doesn't apply so nicely in quantum mechanics. In fact, the quantum version will even show recurrences at some times, where the state goes back to resemble the original state. I have not tried to find these recurrence times and they are likely very long, given that there are dozens of slightly distinct frequencies are at play here.

Technical details:

The ensemble starts out as roughly a rectangle in phase space (with blurred edges as necessary due to uncertainty principle); it was constructed using a statistical mixture of hundreds of gaussian wavepackets of various center positions and center momenta. Because they overlap, however, this doesn't mean there are hundreds of different distinct states. Rather, its von neumann entropy is only 2.368×k, i.e., by Schmidt decomposition it can be roughly approximated as a mixture of something like exp(2.368) ≈ 11 distinct pure states. In terms of the energy eigenstates, it spans about 42 energy eigenstates, but with significant correlations. Since the time-evolution is unitary, the von neumann entropy does not change with time.

In contrast the equilibrated counterpart to this (see image) has higher entropy of 3.739×k, i.e., roughly ~42 distinct pure states. These equilibium pure states are the energy eigenstates: the time-averaging removes all the correlations between energy eigenstates of differing energy, and since all the energies are distinct in this case, the equilibrated version is a simple diagonal density matrix in the energy eigenbasis.

The simulation only included the right-side potential well of this double-well potential, for reasons of speed. This artificially forbids quantum tunnelling to the left well, but we would not expect significant tunnelling to ever occur anyway because this is an asymmetric double well which has not been finely tuned to resonance. Not being tuned for resonance, this means the left-well and right-well energy ladders won't line up (unless by accident) to within the required degree, and so the eigenstates of the two wells will not hybridize and will instead remain cleanly separated into almost purely left-side and purely right-side eigenstates.
Date
Source Travail personnel
Auteur Nanite

Conditions d’utilisation

Moi, en tant que détenteur des droits d’auteur sur cette œuvre, je la publie sous la licence suivante :
Creative Commons CC-Zero Ce fichier est disponible selon les termes de la licence Creative Commons CC0 Don universel au domaine public.
La personne qui a associé une œuvre avec cet acte l’a placée dans le domaine public en renonçant mondialement à tous ses droits sur cette œuvre en vertu des lois relatives au droit d’auteur, ainsi qu’à tous les droits juridiques connexes et voisins qu’elle possédait sur l’œuvre, sans autre limite que celles imposées par la loi. Vous pouvez copier, modifier, distribuer et utiliser cette œuvre, y compris à des fins commerciales, sans qu’il soit nécessaire d’en demander la permission.

Source

 
Cette représentation graphique a été créée avec Matplotlib.

Python source code. Requires matplotlib; ffmpeg to encode frames to a movie.

#!/usr/bin/env python3
"""
Quantum mixed state evolver, and wigner distribution plotter.

Basic strategy:
- Use a spatial finite-difference scheme with not too many pixels. Just
  enough that pixelization doesn't become an issue (i.e., at least a few points
  per wavelength), but not so much that it becomes ridiculously slow.
- Just use full eigen-decomposition of the hamiltonian, don't bother with any
  time-stepping stuff.
- Create a density matrix by statistically superimposing various gaussian wave
  packet pure-states.
- Calculate density matrix in energy basis at any time in future, easy since
  the evolution operator is diagonal in this basis.
- Convert to wigner distribution by:
  - first transforming to the position basis,
  - then using a fourier transform trick (wigner distribution is just fourier
    transform of the antidiagonals!)
"""

from pylab import *

rc('text', usetex=True) ; rc('savefig', dpi=300)

### Parameters
# Very important number, smaller means more classical (finer-spaced discrete levels, larger means more quantum (fewer discrete levels)
hbar = 0.10/(2*pi)

def potential(x):
    return x**6 + 4*x**3 - 5*x**2 - 4*x
# the position-space:
x = linspace(-0.4,1.4,751)
N = len(x)
dx = x[1] - x[0]
U = potential(x)
mass = 1.0
# As an optimization we will throw away all high-energy eigenstates. They are going to
# be trash due to high spatial frequency (so finite-difference momentum is not
# accurate), and they just slow things down.
eig_cutoff = 100

### Calculate the Hamiltonian H = U + hbar^2 (d/dx)^2/2m
# Potential energy goes on diagonal of hamitonian
H = diag(U)
# For the kinetic energy operator (-hbar^2/(2*m) * d^2/dx^2), the usual central difference
# approximation will be used. These go on diagonal and off-diagonals.
H.flat[0::len(x)+1] += hbar*hbar/(mass*dx*dx) # on diagonal
H.flat[1::len(x)+1] += -0.5*hbar*hbar/(mass*dx*dx) # upper diagonal
H.flat[len(x)::len(x)+1] += -0.5*hbar*hbar/(mass*dx*dx) # lower diagonal

# Diagonalize the hamiltonian and cut off high energies
eigval, eigvec = eigh(H)
eigval = eigval[:eig_cutoff]
eigvec = eigvec[:,:eig_cutoff]
eigvec_H = conj(eigvec.T)
# This is basically the true hamiltonian we are going to model, with cutoff.
H_actual = eigvec @ diag(eigval) @ eigvec_H

### Prepare a density matrix (in energy eigenvector space) for time=0
rho_E = np.zeros((len(eigval), len(eigval)), dtype=complex)
# Use gaussian wavepacket pure states, then create a mixture with an uncertainty
# in the wavepacket position and momentum.
xwidth = sqrt(hbar)*0.33 ; countx = int(2 * 0.5 // xwidth)
pwidth = 0.5*hbar/xwidth ; county = int(2 * 2 // pwidth)
print(f"using {countx}*{county} wavepackets with sigma_x = {xwidth:.4f} and sigma_p = {pwidth:.4f}")
for x0 in linspace(0 + xwidth, 0.5 - xwidth, countx):
    for p0 in linspace(-1 + pwidth, 1 - pwidth, county):
        # make the packet and decompose it into eigenbasis
        packet = ((xwidth/dx)**2 * 2*pi)**(-0.25) * exp(-(x - x0)**2 / (2*xwidth)**2 + (1j * p0 / hbar)*x)
        decomp = eigvec_H @ packet
        # add it to matrix
        rho_E += decomp[:, None] * conj(decomp)
# normalize it
rho_E /= trace(rho_E)
assert np.all(rho_E == rho_E.T.conj()), "must be hermitian"

# It is straightforward to time-evolve rho_E

def rho_E_time(rho_E, t):
    # unitarily evolve the rho_E -- easy since it's the energy basis so
    # the unitary operator U = exp(-iHt/hbar) is diagonal.
    # rho(t) = U(t) rho(0) U(t)^h    so this is elementwise multiply by a phase shift.
    Ediff = eigval[:,None] - eigval
    return exp((-1j * t/hbar) * Ediff) * rho_E
# It's also straightforward to calculate rho_x (the position-basis density matrix).
def rho_x_from_E(rho_E):
    return eigvec @ rho_E @ eigvec_H

# Define some parameters of the wigner transform
wig_Np = int(1.5*N) # increase the ordinary momentum resolution by padding
wig_dp = hbar*pi/(dx*wig_Np) # p resolution
wig_p0 = -(wig_Np//2)*wig_dp
wig_extent = (x[0] - 0.5*dx,
              x[-1] + 0.5*dx,
              wig_p0 - 0.5*wig_dp,
              wig_p0 + (wig_Np + 0.5)*wig_dp)

def wignerify(rho_x):
    """ compute wigner transform of space-basis density matrix """
    # We want to FFT along the antidiagonals: [A] , [aBc], [bCd], and [D]
    # To do so we'll 'rotate the matrix' anticlockwise by 45 degrees
    #         ----        ----
    #        |Axax|      | ab |
    #        |xBxb|  --> |ABCD|
    #        |cxCx|      | cd |
    #        |xdxD|      |    |
    #         ----        ----
    # (this puts the diagonals onto rows)
    # The dropped 'x' elements contain mostly redundant information. They
    # could be included but that requires extra computation due to how they straddle
    # across the diagonal.
    Nx = len(rho_x)
    rhoflat = rho_x.ravel('C')
    rho_rot = np.zeros((Nx,Nx), dtype=complex, order='F')
    for i,row in enumerate(rho_rot):
        diagnum = (Nx - 1) // 2 - i
        if diagnum >= 0:
            row[diagnum:Nx-diagnum] = rhoflat[2*diagnum:Nx*(Nx+1-2*diagnum):Nx+1]
        else:
            row[-diagnum:Nx+diagnum] = rhoflat[-2*diagnum*Nx::Nx+1]

    # Fourier transform along the columns.
    res = fft(rho_rot, n = wig_Np, axis=0)
    # deshift the Nx // 2
    res *= exp((2j*pi*(Nx//2)/wig_Np) *  arange(wig_Np)[:,None])
    # Since input rho_x was hermitian, the wigner transform has no imaginary part
    # aside from numerical errors.
    res = res.real
    # put 0 momentum in middle and then snip to size
    res = np.roll(res, wig_Np//2, axis=0)
    return (1./(pi * hbar)) * res

def wigplot(wigner):
    fig = figure(figsize=(4,3))
    ax = axes((0.06,0.07,0.87,0.86))
    ax.set_xlim(-0.20,1.38)
    ax.set_ylim(-3.4,3.4)
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_xlabel('position $x$')
    ax.set_ylabel('momentum $p$')

    ax.imshow(wigner,
              origin='lower left', extent=wig_extent,
              aspect='auto', cmap = matplotlib.cm.RdBu,
              interpolation='bicubic',
              norm=matplotlib.colors.SymLogNorm(linthresh=0.2, linscale=0.5,
                                                vmin=-4, vmax=4),
              )

    # add a rectangle to represent area of hbar
    hbarx = sqrt(hbar) * 0.40
    hbary = hbar/hbarx
    ax.add_artist(Rectangle((-0.07,-3.3),
                  hbarx*sqrt(2*pi), hbary*sqrt(2*pi), facecolor=(0.6,0.85,0.6), edgecolor='k', linewidth=0.5, linestyle='--'))
    ax.text(-0.07-0.01, -3.3 + 0.5*hbary*sqrt(2*pi), r'$h = {}\quad$', ha='right', va='center')

    ax.add_artist(Rectangle((-0.07,-2.4),
                  hbarx, hbary, facecolor=(0.6,0.85,0.6), edgecolor='k', linewidth=0.5, linestyle='--'))
    ax.text(-0.07-0.01, -2.4 + 0.5*hbary, r'$\hbar = {}\quad$', ha='right', va='center')

    # draw marginal x- and p- probability distributions on edges of plot
    ax_Px = axes((0.06, 0.93, 0.87, 0.07))
    ax_Px.axis('off')
    ax_Px.set_xlim(*ax.get_xlim())
    ax_Px.set_ylim(0,5.4)
    Px = np.sum(wigner, axis=0) * wig_dp
    ax_Px.fill_between(x, 0, Px, facecolor='#1f77b4')

    ax_Pp = axes((0.93, 0.07, 0.07, 0.86))
    ax_Pp.axis('off')
    ax_Pp.set_ylim(*ax.get_ylim())
    ax_Pp.set_xlim(0,1.0)
    Py = np.sum(wigner, axis=1) * dx
    ax_Pp.fill_betweenx(wig_p0 + arange(len(Py))*wig_dp, 0, Py, facecolor='#1f77b4')

    return fig, ax

def entropy(rho):
    rho_ev = eigvalsh(rho)
    return -sum(rho_ev * nan_to_num(log(rho_ev)))

#%%
# plot some eigenstates
def plot_eig(n):
    rho = zeros_like(rho_E) ; rho[n][n] = 1.
    assert entropy(rho) == 0.
    fig, ax = wigplot(wignerify(rho_x_from_E(rho_E_time(rho, 0))))
    fig.savefig(f'wigner_eigenstate_{n}.png')
plot_eig(0)
plot_eig(5)
plot_eig(30)
plot_eig(40)

#%%
# plot the equilibrated distribution
rho_E_equilib = rho_E * eye(len(rho_E))
fig, ax = wigplot(wignerify(rho_x_from_E(rho_E_time(rho_E_equilib, 0))))
fig.savefig('wigner_equilibrated.png')
# plot the initial distribution
fig, ax = wigplot(wignerify(rho_x_from_E(rho_E_time(rho_E, 0))))
fig.savefig('wigner_initial.png')
print(f"Initial entropy = {entropy(rho_E)}")
print(f"Equilibrated entropy = {entropy(rho_E_equilib)}")

#%%
# plot the significant (99.9%) Schmidt-decomposed pure states at times 0,0.5,1
def schmidt(rho_E, label):
    rho_eigval, rho_eigvec = eigh(rho_E)
    cumprob = 0.
    for i,(prob, vec) in enumerate(zip(rho_eigval[::-1], rho_eigvec.T[::-1])):
        cumprob += prob
        vec_x = eigvec @ vec # pure wavefunction in x space
        rho_x = vec_x[:,None] @ conj(vec_x)[None,:]
        fig, ax = wigplot(wignerify(rho_x))
        fig.text(0.5, 0.90, f'schmidt[{i}] {label} prob={prob:.3f}', ha='center', va='top')
        # plot
        ax.plot(x,10*vec_x.real+2., color='lime', ls='solid', lw=0.3, ms=1., mew=0.2, marker='+')
        ax.plot(x,10*vec_x.imag+2., color='lime', ls='dashed', lw=0.3)
        fig.savefig(f'schmidt/schmidt[{i}] {label}.png')
        close(fig)
        if cumprob > 0.999:
            break
schmidt(rho_E_time(rho_E,0.), label='t=0.0')
schmidt(rho_E_time(rho_E,0.5), label='t=0.5')
schmidt(rho_E_time(rho_E,1.), label='t=1.0')

# make a movie

framerate = 24
speed = 1.0 # how many time units per second
dt = speed / framerate

for i in range(0,741):
    if i <= 500:
        text = None
        t = i * dt
    elif i <= 620:
        # jump forward to a late time
        text = 'one hour later'
        t = 3600*speed + i * dt
    elif i <= 740:
        # jump forward to a late time
        text = 'one year later'
        t = 365.2425*86400*speed + i * dt
    wigner = wignerify(rho_x_from_E(rho_E_time(rho_E, t)))

    print(f"frame {i: 4d} range {amin(wigner):.03f} to {amax(wigner):.03f}")
    sys.stdout.flush()
    fig, ax = wigplot(wigner)
    if text:
        fig.text(0.5, 0.90, text, ha='center', va='top')
    fig.savefig(f'wigframes/frame{i:04d}.png')
    close(fig)

# commands to make the video file:
# cmd='ffmpeg -framerate 24 -f image2pipe -i - -crf 20 -b:v 0 -an -c:v libvpx-vp9'
# cat wigframes/*.png | $cmd -pass 1 -f webm -y /dev/null
# cat wigframes/*.png | $cmd -pass 2 -y out-full-20-vp9.webm

Légendes

Ajoutez en une ligne la description de ce que représente ce fichier

Éléments décrits dans ce fichier

dépeint

video/webm

Historique du fichier

Cliquer sur une date et heure pour voir le fichier tel qu'il était à ce moment-là.

Date et heureVignetteDimensionsUtilisateurCommentaire
actuel6 septembre 2023 à 05:5731 s, 1 200 × 900 (14,12 Mio)Nanitehigher quality (too bad, prev upload couldn't prevent the wiki transcoder)
5 septembre 2023 à 22:3531 s, 480 × 360 (4,81 Mio)Nanitechanged to vp8 encoding and 360p in hope of avoiding the default low quality transcode being delivered to readers
6 juillet 2020 à 00:4331 s, 600 × 450 (3,71 Mio)Nanitemore tweaks
4 juillet 2020 à 08:3331 s, 600 × 450 (3,72 Mio)Naniteadd hbar-area indicator, and add x- and p- probability distributions
30 juin 2020 à 16:0731 s, 600 × 450 (3,72 Mio)NaniteUploaded own work with UploadWizard

La page suivante utilise ce fichier :

Usage global du fichier

Les autres wikis suivants utilisent ce fichier :

Métadonnées