-
Notifications
You must be signed in to change notification settings - Fork 127
Description
Hi my issue is the following.
System setup
################
I am trying to measure the following quantity
where the hamiltonian
-
$|\psi\rangle$ is a randomly prepared state from a quimb circuit generated by calling the function random_state_prep_circuit_quimb() defined below.
I am implementing
-
Using in-built TEBD (by calling the function in_built_TEBD() defined below) which is internal to quimb. I take the MPS from TEBD using at_times() command and then contract it against the initial random MPS (see above in point 1).
-
Using a circuit-based construction of second-order Trotterization of 1D XXZ obtained from a paper (snapshot shared below) . The circuit is correct and has been replicated in many papers.
I generate the circuit object in quimb , apply relevant gates and then extract the circuit MPS and then contract it against the initial random MPS (see above in point 1). I am using just 4 qubits for testing now and the parameters of XXZ is Jx=Jy=Jz=J. I have set dt = 0.1/J upto 40/J total timesteps . J is set to 1.
Issue/Problem statement
####################
While 2) above works fine and gives expected outcomes, the fidelities
. I have tried many different things including increasing the bond dimension of the MPS representation of the circuit but to no avail. I would just like to ensure if I am doing something odd (which I suspect). All code required for minimal reproduction of the issue is provided below
Any help will be greatly appreciated.
Code and Function base
#####################
def Hamiltonian_generation(system_size, spin_type=1/2, bound_cond='obc', coeff_vector=[1,1,1],
on_site=None):
L=system_size
builder = qtn.SpinHam1D(S=spin_type)
if bound_cond == 'obc':
connectivity_list = [(i,i+1) for i in np.arange(L-1)]
else:
connectivity_list = [(i,i+1) for i in np.arange(L-1)] + [(L-1, 0)]
for qubit_tuple in connectivity_list:
builder[qubit_tuple[0], qubit_tuple[1]] += coeff_vector[0], 'X', 'X'
builder[qubit_tuple[0], qubit_tuple[1]] += coeff_vector[1], 'Y', 'Y'
builder[qubit_tuple[0], qubit_tuple[1]] += coeff_vector[2], 'Z', 'Z'
if on_site != None:
for qubit in np.arange(L):
builder[qubit] += on_site[0], 'X'
builder[qubit] += on_site[1], 'Y'
builder[qubit] += on_site[2], 'Z'
H = builder.build_local_ham(L)
return H
from scipy.stats import rv_continuous
class sin_sampler_dist(rv_continuous):
def _pdf(self, theta):
return 0.5*np.sin(theta)
sin_sampler = sin_sampler_dist(a=0, b=np.pi)
def random_state_prep_circuit_quimb(circuit, system_size, no_layers=3):
from numpy.random import uniform
#circ = qtn.Circuit(system_size, tag_gate_numbers=True, tag_gate_rounds=True, tag_gate_labels=True)
regs = list(range(system_size))
sin_sampler = sin_sampler_dist(a=0, b=np.pi)
even_odd_pair_list = [[(i,i+1) for i in np.arange(0, system_size-1, 2)], [(i,i+1) for i in np.arange(1, system_size-1, 2)]]
for _ in range(no_layers):
for connectivity_list in even_odd_pair_list:
for pair in connectivity_list:
circuit.apply_gate('RZ', uniform(-np.pi, np.pi), regs[pair[0]])
circuit.apply_gate('RY', float(sin_sampler.rvs(size=1)), regs[pair[0]])
circuit.apply_gate('RZ', uniform(-np.pi, np.pi), regs[pair[0]])
circuit.apply_gate('RZ', uniform(-np.pi, np.pi), regs[pair[1]])
circuit.apply_gate('RY', float(sin_sampler.rvs(size=1)), regs[pair[1]])
circuit.apply_gate('RZ', uniform(-np.pi, np.pi), regs[pair[1]])
circuit.apply_gate('CZ', regs[pair[0]], regs[pair[1]])
#circ.apply_gate('CNOT', regs[pair[0]], regs[pair[1]])
return circuit
def unitary_2_qubit_infinitesimal_quimb(circuit, dt, coeff_vector, pair):
import quimb
theta_x = dt*coeff_vector[0]*(0.25**0)
theta_y = dt*coeff_vector[1]*(0.25**0)
theta_z = dt*coeff_vector[2]*(0.25**0)
circuit.apply_gate('CX',pair[0],pair[1])
circuit.apply_gate('RX',2*theta_x, pair[0])
circuit.apply_gate('RZ',2*theta_z, pair[1])
circuit.apply_gate('H',pair[0])
circuit.apply_gate('CX',pair[0], pair[1])
#circuit.apply_gate('RZ',-np.pi/2, pair[0])
circuit.apply_gate("PHASE", -np.pi/2, pair[0])
circuit.apply_gate('H',pair[0])
circuit.apply_gate('RZ',-2*theta_y, pair[1])
circuit.apply_gate('CX',pair[0], pair[1])
circuit.apply_gate('RX',np.pi/2, pair[0])
circuit.apply_gate('RX',-np.pi/2, pair[1])
return circuit
#return quimb.core.dag(circuit.uni)
def time_evolution_finite_quimb(quimb_circ, system_size, dt, No_trotter_steps, coeff_vector, on_site=[0,0,0]):
for step_index in np.arange(1, No_trotter_steps+1):
if on_site not in [None, [0,0,0]]:
for qubit in np.arange(0, system_size):
unitary_1_qubit_infinitesimal_quimb(quimb_circ, qubit, delta_t=dt/2.0, on_site=on_site)
for pair in [(i,i+1) for i in np.arange(0, system_size, 2)]:
quimb_circ = unitary_2_qubit_infinitesimal_quimb(quimb_circ, dt/2.0, coeff_vector, pair)
for pair in [(i,i+1) for i in np.arange(1, system_size-1, 2)]:
quimb_circ = unitary_2_qubit_infinitesimal_quimb(quimb_circ, dt, coeff_vector, pair)
for pair in [(i,i+1) for i in np.arange(0, system_size, 2)]:
quimb_circ = unitary_2_qubit_infinitesimal_quimb(quimb_circ, dt/2.0, coeff_vector, pair)
if on_site not in [None, [0,0,0]]:
for qubit in np.arange(0, system_size):
unitary_1_qubit_infinitesimal_quimb(quimb_circ, qubit, delta_t=dt/2.0, on_site=on_site)
return quimb_circ
def in_built_TEBD(Ham_Local_Ham1D, initial_state_MPS,
total_time_list, dt=1e-2):
tebd = qtn.TEBD(initial_state_MPS, Ham_Local_Ham1D, dt=dt, split_opts=dict(cutoff=1e-8), imag=False)
#ts = np.linspace(0.0, 10.0, 51)
fidelity_dict = {}
fidelity_dict[0] = (abs(initial_state_MPS.H @ initial_state_MPS)**2)
for index, psi_t in enumerate(tebd.at_times(total_time_list, dt=dt, order=2, progbar=False)):
fidelity_dict[total_time_list[index]] = (abs(initial_state_MPS.H @ psi_t)**2)
return fidelity_dict
Results
########
#System attributes and Hamiltonian generation (as LocalHam1D object)
###################################
system_size=4
spin_type=1/2
on_site=[0.0,0.0,0.0]
coeff_vector = [1,1,1]
no_random_states = 1
max_bond_dim = 20
Hamiltonian_params = {'bound_cond' : 'obc', 'coeff_vec' : coeff_vector, 'on-site' : on_site}
total_no_steps = 40
dt = 0.1
inds = 'd_{}'
Ham_Local_Ham1D = Hamiltonian_generation(system_size=system_size, spin_type=1/2,
bound_cond=Hamiltonian_params['bound_cond'],
coeff_vector=Hamiltonian_params['coeff_vec'],
on_site=Hamiltonian_params['on-site'])
#Initial random state prep
#*************************
circuit = qtn.Circuit(system_size)
regs = list(range(system_size))
quimb_rand_circuit = random_state_prep_circuit_quimb(circuit, system_size=system_size, no_layers=1)
quimb_rand_circuit_MPS = qtn.CircuitMPS.from_gates(gates=quimb_rand_circuit.gates,
gate_opts=dict(
max_bond=10*max_bond_dim,
cutoff=1e-8),
progbar=False,
).psi
#In-built TEBD call with initial random state
#***********************************
ovlp_inbuilt = in_built_TEBD(Ham_Local_Ham1D=Ham_Local_Ham1D, initial_state_MPS=quimb_rand_circuit_MPS,
total_time_list=np.round(np.multiply(dt, np.arange(1, total_no_steps+1)), 3), dt=dt)
print ("ovlp inbuilt", ovlp_inbuilt)
#quimb circuit TEBD call with initial random state
#************************************************
for time in tqdm(np.round(np.multiply(dt, np.arange(1, total_no_steps+1)), 3)):
quimb_rand_circuit = time_evolution_finite_quimb(quimb_rand_circuit, system_size, dt, No_trotter_steps=1, coeff_vector = coeff_vector, on_site=on_site)
ovlp_quimb_circ[time] = np.abs(quimb_rand_circuit.psi.H @ quimb_rand_circuit_MPS)**2
print ("ovlp quimb circuit", ovlp_quimb_circ)
Obtained values are the following :
ovlp inbuilt
{0: 0.9999999999999996, 0.1: 0.9959420262043145, 0.2: 0.983891407115981, 0.3: 0.9642130056409608, 0.4: 0.9374983467005762, 0.5: 0.9045415526145574, 0.6: 0.8663072221496924, 0.7: 0.8238917291899889, 0.8: 0.778479710461427, 0.9: 0.7312977182400782, 1.0: 0.6835671237596156, 1.1: 0.6364583653384801, 1.2: 0.5910485424703097, 1.3: 0.5482841687956572, 1.4: 0.5089506233444718, 1.5: 0.4736494953004309, 1.6: 0.44278462084450815, 1.7: 0.4165571819382002, 1.8: 0.39496979816803934, 1.9: 0.37783911620853705, 2.0: 0.36481600838146555, 2.1: 0.3554121514988259, 2.2: 0.34903148598357875, 2.3: 0.3450048656601664, 2.4: 0.3426261086650983, 2.5: 0.34118765292126413, 2.6: 0.34001410391814757, 2.7: 0.33849213176064225, 2.8: 0.33609541785946806, 2.9: 0.33240365478653927, 3.0: 0.3271149483662977, 3.1: 0.3200513397526423, 3.2: 0.31115753692245507, 3.3: 0.3004932998064056, 3.4: 0.2882202425838816, 3.5: 0.2745840841878343, 3.6: 0.25989358062978857, 3.7: 0.24449750100147927, 3.8: 0.22876105782765893, 3.9: 0.2130431711909683, 4.0: 0.19767583851098744}
100%|███████████████████████████████████████████| 40[/40]
ovlp quimb circuit
{0: 0.9999999999997653, 0.1: 0.9369746964571253, 0.2: 0.7765595355083472, 0.3: 0.5873344146119812, 0.4: 0.43750202815996575, 0.5: 0.3587113866866219, 0.6: 0.3366132595640836, 0.7: 0.3308098581783994, 0.8: 0.30668543275393273, 0.9: 0.25586642990003705, 1.0: 0.19367291099489414, 1.1: 0.140509402319722, 1.2: 0.10488567232900191, 1.3: 0.0812364807836786, 1.4: 0.06121836858943995, 1.5: 0.04557161888610211, 1.6: 0.04443007843526534, 1.7: 0.06561253470317936, 1.8: 0.10221747955819366, 1.9: 0.13227159026992924, 2.0: 0.1329210655233114, 2.1: 0.09855090483145529, 2.2: 0.047674796368554234, 2.3: 0.011693423760589221, 2.4: 0.01310025279069152, 2.5: 0.0495034260404082, 2.6: 0.09560474983328712, 2.7: 0.12138942900862644, 2.8: 0.11246525862569816, 2.9: 0.07755055252846635, 3.0: 0.038910997546266854, 3.1: 0.014928113082244105, 3.2: 0.009054006524575536, 3.3: 0.012589849241910476, 3.4: 0.01647299874239502, 3.5: 0.0202763181419398, 3.6: 0.030614666162991806, 3.7: 0.0520115464150108, 3.8: 0.08083538376318122, 3.9: 0.10999796024130568, 4.0: 0.14106762557191635}