Overview of dynamite: implementing a long-range Ising model

Let's implement a power law long-range ZZ interaction with open boundary conditions and some uniform field. Our Hamiltonian is

$$H = \sum_{i,j} \frac{J}{\left| i-j \right| ^ \alpha} \sigma^z_i \sigma^z_j + \vec{h} \cdot \sum_i \vec{\sigma}_i$$

where $J$ is the interaction strength, $\alpha$ is the power-law decay with distance between sites, and the vector $\vec{h}$ is the static, uniform field.

First we import the things we will need:


In [1]:
from dynamite import config
from dynamite.operators import sigmax, sigmay, sigmaz, op_sum, index_sum

Let's set the spin chain length to 8 globally for the purposes of this example. However, note that you aren't required to set the spin chain length before you start building your operator!


In [2]:
config.L = 8

Now we start building up our Hamiltonian. Here is a ZZ interaction between site 0 and site 2:


In [3]:
sigmaz(0)*sigmaz(2)


Out[3]:
$\sigma^z_{0}\sigma^z_{2}$

Let's take such an interaction and translate it along the spin chain. Note that the sum is to $i=5$ such that the operator has support on all spins of our length 8 chain (which is indexed from 0).


In [4]:
index_sum(sigmaz(0)*sigmaz(2))


Out[4]:
$\sum_{i=0}^{5}\sigma^z_{i}\sigma^z_{i+2}$

Sometimes it's more informative to have a term-by-term look at the operator:


In [5]:
oper = index_sum(sigmaz(0)*sigmaz(2))
print(oper.table())


   coeff. | operator 
=====================
    1.000 | Z-Z-----
    1.000 | -Z-Z----
    1.000 | --Z-Z---
    1.000 | ---Z-Z--
    1.000 | ----Z-Z-
    1.000 | -----Z-Z

Looks good! Let's create our power law. Here we are using op_sum, which takes the sum of the operators in the iterable passed to it. In our case, we will use a python generator as the argument.


In [6]:
alpha = 1.15
long_range_zz = op_sum(1/(d**alpha) * index_sum(sigmaz(0)*sigmaz(d)) for d in range(1,8))

Now what does the interaction look like?


In [7]:
long_range_zz


Out[7]:
$1.000*\left[\sum_{i=0}^{6}\sigma^z_{i}\sigma^z_{i+1}\right] + 0.451*\left[\sum_{i=0}^{5}\sigma^z_{i}\sigma^z_{i+2}\right] + 0.283*\left[\sum_{i=0}^{4}\sigma^z_{i}\sigma^z_{i+3}\right] + \cdots$

Nice! now that we have our long-range power law interaction, we just need the static, uniform field.


In [8]:
# the x, y, z components of the field
h = [0.5, 0.2, 0.1]
sigma = [sigmax, sigmay, sigmaz]

static_field = op_sum(hi*index_sum(sigmai()) for hi,sigmai in zip(h,sigma))
static_field


Out[8]:
$0.500*\left[\sum_{i=0}^{7}\sigma^x_{i}\right] + 0.200*\left[\sum_{i=0}^{7}\sigma^y_{i}\right] + 0.100*\left[\sum_{i=0}^{7}\sigma^z_{i}\right]$

Then our Hamiltonian is just the sum of these two:


In [9]:
H = long_range_zz + static_field

With that, we can do whatever computations we want! For example, solving for the ground state energy:


In [10]:
energies = H.eigsolve()
print(energies[0])


-6.435647428300428

or evolve a product state for some time:


In [11]:
from dynamite.states import State

# specify the initial state as a product state with one domain wall
initial_state = State(state='UUUUDDDD')

result = H.evolve(initial_state, t=5.0)

# compute overlap with initial state
overlap = abs(initial_state.dot(result))
print('overlap:', overlap)


overlap: 0.4076078507915722

or do imaginary time evolution from a random state to find a thermal state of some $\beta$:

$$\left| \psi_\beta \right> = e^{-\beta H} \left| \psi_r \right> = e^{-i (-i t_\beta) H} \left| \psi_r \right> $$

where $\left| \psi_r \right>$ is a random state.


In [12]:
beta = 1.5
imag_time = -1j*beta

random_state = State(state='random')
thermal_state = H.evolve(random_state, t=imag_time)
thermal_state.normalize()

# print the expectation values of the energy for the two states
random_state_energy = random_state.dot(H*random_state).real
thermal_state_energy = thermal_state.dot(H*thermal_state).real

print('E random:', random_state_energy)
print('E thermal:', thermal_state_energy)


E random: -0.12540121634250848
E thermal: -6.161228980108254

As expected, the "cold" thermal state has lower energy.