Skip to content

Commit

Permalink
Qtrl split unitary tests (#600)
Browse files Browse the repository at this point in the history
* The first test from test_control_pulseoptim split
Now 6 separate tests.
Some other tests also split
All tests re-numbered
  • Loading branch information
ajgpitch committed Jan 1, 2017
1 parent 95a56b4 commit 6c0565f
Showing 1 changed file with 263 additions and 19 deletions.
282 changes: 263 additions & 19 deletions qutip/tests/test_control_pulseoptim.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ def tearDown(self):
shutil.rmtree(d, ignore_errors=True)


def test_1_unitary(self):
def test_01_1_unitary_hadamard(self):
"""
control.pulseoptim: Hadamard and QFT gate with linear initial pulses
control.pulseoptim: Hadamard gate with linear initial pulses
assert that goal is achieved and fidelity error is below threshold
"""
# Hadamard
Expand Down Expand Up @@ -175,18 +175,177 @@ def test_1_unitary(self):
err_msg="Direct and indirect methods produce "
"different results for Hadamard")

# QFT
def test_01_2_unitary_hadamard_no_stats(self):
"""
control.pulseoptim: Hadamard gate with linear initial pulses (no stats)
assert that goal is achieved
"""
# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

n_ts = 10
evo_time = 10

# Run the optimisation
#Try without stats
result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-10,
init_pulse_type='LIN',
gen_stats=False)
assert_(result.goal_achieved, msg="Hadamard goal not achieved "
"(no stats). "
"Terminated due to: {}, with infidelity: {}".format(
result.termination_reason, result.fid_err))

def test_01_3_unitary_hadamard_tau(self):
"""
control.pulseoptim: Hadamard gate with linear initial pulses (tau)
assert that goal is achieved
"""
# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

# Run the optimisation
#Try setting timeslots with tau array
tau = np.arange(1.0, 10.0, 1.0)
result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
tau=tau,
fid_err_targ=1e-10,
init_pulse_type='LIN',
gen_stats=False)
assert_(result.goal_achieved, msg="Hadamard goal not achieved "
"(tau as timeslots). "
"Terminated due to: {}, with infidelity: {}".format(
result.termination_reason, result.fid_err))

def test_01_4_unitary_hadamard_qobj(self):
"""
control.pulseoptim: Hadamard gate with linear initial pulses (Qobj)
assert that goal is achieved
"""
# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

n_ts = 10
evo_time = 10

# Run the optimisation
#Try with Qobj propagation
result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-10,
init_pulse_type='LIN',
dyn_params={'oper_dtype':Qobj},
gen_stats=True)
assert_(result.goal_achieved, msg="Hadamard goal not achieved "
"(Qobj propagation). "
"Terminated due to: {}, with infidelity: {}".format(
result.termination_reason, result.fid_err))

def test_01_5_unitary_hadamard_oo(self):
"""
control.pulseoptim: Hadamard gate with linear initial pulses (OO)
assert that goal is achieved and pulseoptim method achieves
same result as OO method
"""
# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

n_ts = 10
evo_time = 10

# Run the optimisation
optim = cpo.create_pulse_optimizer(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-10,
dyn_type='UNIT',
init_pulse_type='LIN',
gen_stats=True)
dyn = optim.dynamics

init_amps = optim.pulse_generator.gen_pulse().reshape([-1, 1])
dyn.initialize_controls(init_amps)

result_oo = optim.run_optimization()

# Run the pulseoptim func
result_po = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-10,
init_pulse_type='LIN',
gen_stats=True)

assert_almost_equal(result_oo.fid_err, result_po.fid_err, decimal=10,
err_msg="OO and pulseoptim methods produce "
"different results for Hadamard")

def test_01_6_unitary_hadamard_grad(self):
"""
control.pulseoptim: Hadamard gate gradient check
assert that gradient approx and exact gradient match in tolerance
"""
# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

n_ts = 10
evo_time = 10

# Run the optimisation
# Check same result is achieved using the create objects method
optim = cpo.create_pulse_optimizer(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-10,
dyn_type='UNIT',
init_pulse_type='LIN',
gen_stats=True)
dyn = optim.dynamics

init_amps = optim.pulse_generator.gen_pulse().reshape([-1, 1])
dyn.initialize_controls(init_amps)

# Check the exact gradient
func = optim.fid_err_func_wrapper
grad = optim.fid_err_grad_wrapper
x0 = dyn.ctrl_amps.flatten()
grad_diff = check_grad(func, grad, x0)
assert_almost_equal(grad_diff, 0.0, decimal=7,
err_msg="Unitary gradient outside tolerance")

def test_02_1_qft(self):
"""
control.pulseoptim: QFT gate with linear initial pulses
assert that goal is achieved and fidelity error is below threshold
"""
Sx = sigmax()
Sy = sigmay()
Sz = sigmaz()
Si = 0.5*identity(2)

H_d = 0.5*(tensor(Sx, Sx) + tensor(Sy, Sy) + tensor(Sz, Sz))
H_c = [tensor(Sx, Si), tensor(Sy, Si), tensor(Si, Sx), tensor(Si, Sy)]
#n_ctrls = len(H_c)
U_0 = identity(4)
# Target for the gate evolution - Quantum Fourier Transform gate
U_targ = qft.qft(2)

n_ts = 10
evo_time = 10

result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-9,
Expand All @@ -209,11 +368,40 @@ def test_1_unitary(self):
assert_((result2.final_amps >= -1.0).all() and
(result2.final_amps <= 1.0).all(),
msg="Amplitude bounds exceeded for QFT")
def test_2_dumping_and_unitarity(self):

def test_02_2_qft_bounds(self):
"""
control: data dumping and unitarity checking
Dump out processing data and use to check unitary evolution
control.pulseoptim: QFT gate with linear initial pulses (bounds)
assert that amplitudes remain in bounds
"""
Sx = sigmax()
Sy = sigmay()
Sz = sigmaz()
Si = 0.5*identity(2)

H_d = 0.5*(tensor(Sx, Sx) + tensor(Sy, Sy) + tensor(Sz, Sz))
H_c = [tensor(Sx, Si), tensor(Sy, Si), tensor(Si, Sx), tensor(Si, Sy)]
U_0 = identity(4)
# Target for the gate evolution - Quantum Fourier Transform gate
U_targ = qft.qft(2)

n_ts = 10
evo_time = 10

result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-9,
amp_lbound=-1.0, amp_ubound=1.0,
init_pulse_type='LIN',
gen_stats=True)
assert_((result.final_amps >= -1.0).all() and
(result.final_amps <= 1.0).all(),
msg="Amplitude bounds exceeded for QFT")

def test_03_dumping(self):
"""
control: data dumping
Dump out processing data, check file counts
"""
N_EXP_OPTIMDUMP_FILES = 10
N_EXP_DYNDUMP_FILES = 49
Expand Down Expand Up @@ -265,13 +453,42 @@ def test_2_dumping_and_unitarity(self):
with open(fpath, 'wb') as f:
optim.dump.writeout(f)

assert_(os.stat(fpath).st_size > 0, msg="Nothing written to optimizer dump file")
assert_(os.stat(fpath).st_size > 0,
msg="Nothing written to optimizer dump file")

fpath = os.path.expanduser(os.path.join('~', str(uuid.uuid4())))
self.tmp_files.append(fpath)
with open(fpath, 'wb') as f:
dyn.dump.writeout(f)
assert_(os.stat(fpath).st_size > 0, msg="Nothing written to dynamics dump file")
assert_(os.stat(fpath).st_size > 0,
msg="Nothing written to dynamics dump file")

def test_04_unitarity(self):
"""
control: unitarity checking (via dump)
Dump out processing data and use to check unitary evolution
"""

# Hadamard
H_d = sigmaz()
H_c = [sigmax()]
U_0 = identity(2)
U_targ = hadamard_transform(1)

n_ts = 1000
evo_time = 4

result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ,
n_ts, evo_time,
fid_err_targ=1e-9,
init_pulse_type='LIN',
dyn_params={'dumping':'FULL'},
gen_stats=True)

# check dumps were generated
optim = result.optimizer
dyn = optim.dynamics
assert_(dyn.dump is not None, msg='dynamics dump not created')

# Use the dump to check unitarity of all propagators and evo_ops
dyn.unitarity_tol = 1e-14
Expand All @@ -291,8 +508,8 @@ def test_2_dumping_and_unitarity(self):
assert_(nu_onto_evo==0,
msg="{} onto evo ops found to be non-unitary".format(
nu_onto_evo))
def test_3_state_to_state(self):

def test_05_1_state_to_state(self):
"""
control.pulseoptim: state-to-state transfer
linear initial pulse used
Expand Down Expand Up @@ -330,7 +547,34 @@ def test_3_state_to_state(self):
result.termination_reason, result.fid_err))
assert_almost_equal(result.fid_err, 0.0, decimal=10,
err_msg="Hadamard infidelity too high")


def test_05_2_state_to_state_qobj(self):
"""
control.pulseoptim: state-to-state transfer (Qobj)
linear initial pulse used
assert that goal is achieved
"""
# 2 qubits with Ising interaction
# some arbitary coupling constants
alpha = [0.9, 0.7]
beta = [0.8, 0.9]
Sx = sigmax()
Sz = sigmaz()
H_d = (alpha[0]*tensor(Sx,identity(2)) +
alpha[1]*tensor(identity(2),Sx) +
beta[0]*tensor(Sz,identity(2)) +
beta[1]*tensor(identity(2),Sz))
H_c = [tensor(Sz,Sz)]

q1_0 = q2_0 = Qobj([[1], [0]])
q1_T = q2_T = Qobj([[0], [1]])

psi_0 = tensor(q1_0, q2_0)
psi_T = tensor(q1_T, q2_T)

n_ts = 10
evo_time = 18

#Try with Qobj propagation
result = cpo.optimize_pulse_unitary(H_d, H_c, psi_0, psi_T,
n_ts, evo_time,
Expand All @@ -343,7 +587,7 @@ def test_3_state_to_state(self):
"Terminated due to: {}, with infidelity: {}".format(
result.termination_reason, result.fid_err))

def test_4_lindbladian(self):
def test_06_lindbladian(self):
"""
control.pulseoptim: amplitude damping channel
Lindbladian dynamics
Expand Down Expand Up @@ -422,7 +666,7 @@ def test_4_lindbladian(self):
err_msg="Direct and indirect methods produce "
"different results for ADC")

def test_5_symplectic(self):
def test_07_symplectic(self):
"""
control.pulseoptim: coupled oscillators (symplectic dynamics)
assert that fidelity error is below threshold
Expand Down Expand Up @@ -519,7 +763,7 @@ def test_5_symplectic(self):
err_msg="Direct and indirect methods produce "
"different results for Symplectic")

def test_6_crab(self):
def test_08_crab(self):
"""
control.pulseoptim: Hadamard gate using CRAB algorithm
Apply guess and ramping pulse
Expand Down Expand Up @@ -576,7 +820,7 @@ def test_6_crab(self):
"Terminated due to: {}, with infidelity: {}".format(
result.termination_reason, result.fid_err))

def test_7_load_params(self):
def test_09_load_params(self):
"""
control.pulseoptim: Hadamard gate (loading config from file)
compare with result produced by pulseoptim method
Expand Down Expand Up @@ -646,7 +890,7 @@ def test_7_load_params(self):
err_msg="Pulses do not match")


def test_8_init_pulse_params(self):
def test_10_init_pulse_params(self):
"""
control.pulsegen: Check periodic control functions
"""
Expand Down Expand Up @@ -707,7 +951,7 @@ def count_waves(n_ts, evo_time, ptype, freq=None, num_waves=None):
"Number of waves incorrect for pulse type '{}', "
"num_waves {}".format(ptype, num_waves))

def test_9_time_dependent_drift(self):
def test_11_time_dependent_drift(self):
"""
control.pulseoptim: Hadamard gate with fixed and time varying drift
assert that goal is achieved for both and that different control
Expand Down

0 comments on commit 6c0565f

Please sign in to comment.