|
| 1 | +"""Exact diagonalization code for the transverse field Ising model with momentum conservation. |
| 2 | +
|
| 3 | +H = -J sum_i sigma^x_i sigma^x_{i+1} - g sum_i sigma^z i; periodic boundary cond. |
| 4 | +
|
| 5 | +""" |
| 6 | + |
| 7 | +import numpy as np |
| 8 | +import scipy.sparse.linalg |
| 9 | +import matplotlib.pyplot as plt |
| 10 | + |
| 11 | + |
| 12 | +def flip(s, i, N): |
| 13 | + """Flip the bits of the state `s` at positions i and (i+1)%N.""" |
| 14 | + return s ^ (1 << i | 1 << ((i+1) % N)) |
| 15 | + |
| 16 | + |
| 17 | +def translate(s, N): |
| 18 | + """Shift the bits of the state `s` one position to the right (cyclically for N bits).""" |
| 19 | + bs = bin(s)[2:].zfill(N) |
| 20 | + return int(bs[-1] + bs[:-1], base=2) |
| 21 | + |
| 22 | + |
| 23 | +def count_ones(s, N): |
| 24 | + """Count the number of `1` in the binary representation of the state `s`.""" |
| 25 | + return bin(s).count('1') |
| 26 | + |
| 27 | + |
| 28 | +def is_representative(s, k, N): |
| 29 | + """Check if |s> is the representative for the momentum state. |
| 30 | +
|
| 31 | + Returns -1 if s is not a representative. |
| 32 | + If |s> is a representative, return the periodicity R, |
| 33 | + i.e. the smallest integer R > 0 such that T**R |s> = |s>.""" |
| 34 | + t = s |
| 35 | + for i in range(N): |
| 36 | + t = translate(t, N) |
| 37 | + if t < s: |
| 38 | + return -1 # there is a smaller representative in the orbit |
| 39 | + elif (t == s): |
| 40 | + if (np.mod(k, N/(i+1)) != 0): |
| 41 | + return -1 # periodicty incompatible with k |
| 42 | + else: |
| 43 | + return i+1 |
| 44 | + |
| 45 | + |
| 46 | +def get_representative(s, N): |
| 47 | + """Find the representative r in the orbit of s and return (r, l) such that |r>= T**l|s>""" |
| 48 | + r = s |
| 49 | + t = s |
| 50 | + l = 0 |
| 51 | + for i in range(N): |
| 52 | + t = translate(t, N) |
| 53 | + if (t < r): |
| 54 | + r = t |
| 55 | + l = i + 1 |
| 56 | + return r, l |
| 57 | + |
| 58 | + |
| 59 | +def calc_basis(N): |
| 60 | + """Determine the (representatives of the) basis for each block. |
| 61 | +
|
| 62 | + A block is detemined by the quantum numbers `qn`, here simply `k`. |
| 63 | + `basis` and `ind_in_basis` are dictionaries with `qn` as keys. |
| 64 | + For each block, `basis[qn]` contains all the representative spin configurations `sa` |
| 65 | + and periodicities `Ra` generating the state |
| 66 | + ``|a(k)> = 1/sqrt(Na) sum_l=0^{N-1} exp(i k l) T**l |sa>`` |
| 67 | +
|
| 68 | + `ind_in_basis[qn]` is a dictionary mapping from the representative spin configuration `sa` |
| 69 | + to the index within the list `basis[qn]`. |
| 70 | + """ |
| 71 | + basis = dict() |
| 72 | + ind_in_basis = dict() |
| 73 | + for sa in range(2**N): |
| 74 | + for k in range(-N//2+1, N//2+1): |
| 75 | + qn = k |
| 76 | + Ra = is_representative(sa, k, N) |
| 77 | + if Ra > 0: |
| 78 | + if qn not in basis: |
| 79 | + basis[qn] = [] |
| 80 | + ind_in_basis[qn] = dict() |
| 81 | + ind_in_basis[qn][sa] = len(basis[qn]) |
| 82 | + basis[qn].append((sa, Ra)) |
| 83 | + return basis, ind_in_basis |
| 84 | + |
| 85 | + |
| 86 | +def calc_H(N, J, g): |
| 87 | + """Determine the blocks of the Hamiltonian as scipy.sparse.csr_matrix.""" |
| 88 | + print("Generating Hamiltonian ... ", end="", flush=True) |
| 89 | + basis, ind_in_basis = calc_basis(N) |
| 90 | + H = {} |
| 91 | + for qn in basis: |
| 92 | + M = len(basis[qn]) |
| 93 | + H_block_data = [] |
| 94 | + H_block_inds = [] |
| 95 | + a = 0 |
| 96 | + for sa, Ra in basis[qn]: |
| 97 | + H_block_data.append(-g * (-N + 2*count_ones(sa, N))) |
| 98 | + H_block_inds.append((a, a)) |
| 99 | + for i in range(N): |
| 100 | + sb, l = get_representative(flip(sa, i, N), N) |
| 101 | + if sb in ind_in_basis[qn]: |
| 102 | + b = ind_in_basis[qn][sb] |
| 103 | + Rb = basis[qn][b][1] |
| 104 | + k = qn*2*np.pi/Ra |
| 105 | + H_block_data.append(-J*np.exp(-1j*k*l)*np.sqrt(Ra/Rb)) |
| 106 | + H_block_inds.append((b, a)) |
| 107 | + # else: flipped state incompatible with the k value, |b(k)> is zero |
| 108 | + a += 1 |
| 109 | + H_block_inds = np.array(H_block_inds) |
| 110 | + H_block_data = np.array(H_block_data) |
| 111 | + H_block = scipy.sparse.csr_matrix((H_block_data, (H_block_inds[:, 0], H_block_inds[:, 1])), |
| 112 | + shape=(M,M),dtype=np.complex) |
| 113 | + H[qn] = H_block |
| 114 | + print("done", flush=True) |
| 115 | + return H |
0 commit comments