-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlattice_hamiltonians.py
179 lines (153 loc) · 7.45 KB
/
lattice_hamiltonians.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import numpy as np
# This code includes functions to generate lattice hamiltonians of arbitrary size with desired connectivity
# and other properties
#Globally define some useful operators that will never be changed:
X = np.array([[0, 1],
[1, 0]])
Z = np.array([[1, 0],
[0, -1]])
Y = np.array([[0, -1j],
[1j, 0]])
I = np.array([[1, 0],
[0, 1]])
XX = np.kron(X, X) #tensor products between two Pauli's
XZ = np.kron(X, Z)
ZZ = np.kron(Z, Z)
ZX = np.kron(Z, X)
II = np.kron(I, I)
IX = np.kron(I, X)
XI = np.kron(X, I)
IZ = np.kron(I, Z)
ZI = np.kron(Z, I)
#Some helper functions for building lattices
# A simple function that computes the graph distance between two sites
def dist(site1, site2):
distance_vec = site1 - site2
distance = np.abs(distance_vec[0]) + np.abs(distance_vec[1])
return distance
# A simple function that initializes a graph in the form of an np.array of coordinates
def initialize_graph(x_sites, y_sites):
coord_list = []
for i in range(x_sites):
for j in range(y_sites):
coord_list.append([i,j])
return np.array(coord_list)
#A funciton that initializes a Pauli operator in the correct space, acting on a specific qubit
def initialize_operator(operator_2d, acting_space, space_dimension):
if acting_space>space_dimension:
return 'error'
for i in range(acting_space):
operator_2d = np.kron(operator_2d, I)
for j in range(space_dimension - acting_space-1):
operator_2d = np.kron(I, operator_2d)
return operator_2d
def initialize_observable(operator_2d, space_dimension):
temp_op = np.copy(operator_2d)
for i in range(space_dimension - 1):
temp_op = np.kron(temp_op, operator_2d)
return temp_op
#Functions that return np arrays (1D lists) containing hamiltonian matrix summands (2D numpy arrays)
#Exponentially decaying local graph hamiltonian. Interactions fall of exponentially with the graph distance
def exp_loc_graph_hamiltonian(x_dim, y_dim, rng_seed):
np.random.seed(rng_seed)
hamiltonian_list = []
graph = initialize_graph(x_dim, y_dim)
for i in range(x_dim*y_dim):
for j in range(y_dim*x_dim):
if i != j: #long range interaction
#alpha = np.random.normal()
hamiltonian_list.append(
np.matmul(initialize_operator(Z, i, x_dim*y_dim), initialize_operator(Z, j, x_dim*y_dim)) *
2.0**(-dist(graph[i], graph[j])))
# if (dist(graph[i], graph[j])==1) and (i>j): #nearest neighbour interaction
# beta = np.random.normal()
# hamiltonian_list.append(beta * np.matmul(initialize_operator(Y, i, x_dim*y_dim), initialize_operator(Y, j, x_dim*y_dim)))
#gamma = np.random.normal()
hamiltonian_list.append(5.0 * initialize_operator(X, i, x_dim*y_dim))
return np.array(hamiltonian_list)
def exp_distr_heisenberg_hamiltonian(length, b_field, rng_seed, b_rand):
#b_rand is a boolean that either sets the field to be randomized or the interactions (if false)
y_dim = 1
x_dim = length #restrict to 1d spin change so we can get more disjoint regions
np.random.seed(rng_seed)
hamiltonian_list = []
indices = []
#graph = initialize_graph(x_dim, y_dim)
operator_set = [X, Y, Z]
lat_points = x_dim*y_dim
for k in operator_set:
for i in range(lat_points):
for j in range (lat_points):
if (i == j+1):
if b_rand == True:
hamiltonian_list.append(1 * np.matmul(initialize_operator(k, i, lat_points), initialize_operator(k, j, lat_points)))
#indices.append([i, j])
else:
alpha = np.random.exponential(scale=0.1)
hamiltonian_list.append(alpha * np.matmul(initialize_operator(k, i, lat_points), initialize_operator(k, j, lat_points)))
#indices.append([i, j])
if np.array_equal(Z, k) == True:
if b_rand == True:
beta = np.random.exponential() #if we want to randomize the field strength reponse at each site (might be unphysical)
hamiltonian_list.append(beta * initialize_operator(k, i, lat_points))
#indices.append([i])
else:
hamiltonian_list.append(b_field * initialize_operator(k, i, lat_points))
#indices.append([i])
return np.array(hamiltonian_list)
def heisenberg_model(length, b_field):
y_dim = 1
x_dim = length #restrict to 1d spin change so we can get more disjoint regions
hamiltonian_list = []
#graph = initialize_graph(x_dim, y_dim)
operator_set = [X, Y, Z]
lat_points = x_dim*y_dim
for k in operator_set:
for i in range(lat_points):
for j in range (lat_points):
if (i == j+1):
hamiltonian_list.append(1 * np.matmul(initialize_operator(k, i, lat_points), initialize_operator(k, j, lat_points)))
if np.array_equal(Z, k) == True:
hamiltonian_list.append(b_field * initialize_operator(k, i, lat_points))
return np.array(hamiltonian_list)
def ising_model(dim, b_field = 0, rng_seed=1):
'''Function does not currently have randomization effects, b_field picks the J/g ratio, where J==1'''
ham_list = []
for i in range(dim):
for j in range(dim):
if ((i==j+1) or (i==0 and j == dim-1)):
ham_list.append(-1 * np.matmul(initialize_operator(Z, i, dim), initialize_operator(Z, j, dim)))
if b_field != 0:
ham_list.append(b_field * initialize_operator(Z, i, dim))
return np.array(ham_list)
#a function that generates the list of hamiltonian terms for a random NN Heinsenberg model with abritrary b_field strength
def local_heisenberg_hamiltonian(length, rng_seed=1, b_rand=False, coupling = 0.05):
#b_rand is a boolean that either sets the field to be randomized or the interactions (if false)
y_dim = 1
x_dim = length #restrict to 1d spin change so we can get more disjoint regions
np.random.seed(rng_seed)
hamiltonian_list = []
indices = []
#graph = initialize_graph(x_dim, y_dim)
operator_set = [X, Y, Z]
lat_points = x_dim*y_dim
for k in operator_set:
for i in range(lat_points):
for j in range (lat_points):
if (i == j+1):
if b_rand == True:
hamiltonian_list.append(1 * np.matmul(initialize_operator(k, i, lat_points), initialize_operator(k, j, lat_points)))
indices.append([i, j])
else:
alpha = np.random.exponential(scale=coupling)
hamiltonian_list.append(alpha * np.matmul(initialize_operator(k, i, lat_points), initialize_operator(k, j, lat_points)))
indices.append([i, j])
if np.array_equal(Z, k) == True:
if b_rand == True:
beta = np.random.random() #if we want to randomize the field strength reponse at each site (might be unphysical)
hamiltonian_list.append(10 * beta * initialize_operator(k, i, lat_points))
indices.append([i])
else:
hamiltonian_list.append(1 * initialize_operator(k, i, lat_points))
indices.append([i])
return (np.array(hamiltonian_list) , indices, length)