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 pulses are produced (only) when they should be """ # Hadamard H_0 = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 20 evo_time = 10 drift_amps_flat = np.ones([n_ts], dtype=float) dript_amps_step = [np.round(float(k)/n_ts) for k in range(n_ts)] # Run the optimisations result_fixed = cpo.optimize_pulse_unitary(H_0, H_c, U_0, U_targ, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result_fixed.goal_achieved, msg="Fixed drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_fixed.termination_reason, result_fixed.fid_err)) H_d = [drift_amps_flat[k]*H_0 for k in range(n_ts)] result_flat = 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_(result_flat.goal_achieved, msg="Flat drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_flat.termination_reason, result_flat.fid_err)) # Check fixed and flat produced the same pulse assert_almost_equal(result_fixed.final_amps, result_flat.final_amps, decimal=9, err_msg="Flat and fixed drift result in " "different control pules") H_d = [dript_amps_step[k]*H_0 for k in range(n_ts)] result_step = 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_(result_step.goal_achieved, msg="Step drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_step.termination_reason, result_step.fid_err)) # Check step and flat produced different results assert_(np.any( np.abs(result_flat.final_amps - result_step.final_amps) > 1e-3), msg="Flat and step drift result in " "the same control pules")
def test_9_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 pulses are produced (only) when they should be """ # Hadamard H_0 = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 20 evo_time = 10 drift_amps_flat = np.ones([n_ts], dtype=float) dript_amps_step = [np.round(float(k)/n_ts) for k in range(n_ts)] # Run the optimisations result_fixed = cpo.optimize_pulse_unitary(H_0, H_c, U_0, U_targ, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result_fixed.goal_achieved, msg="Fixed drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_fixed.termination_reason, result_fixed.fid_err)) H_d = [drift_amps_flat[k]*H_0 for k in range(n_ts)] result_flat = 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_(result_flat.goal_achieved, msg="Flat drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_flat.termination_reason, result_flat.fid_err)) # Check fixed and flat produced the same pulse assert_almost_equal(result_fixed.final_amps, result_flat.final_amps, decimal=9, err_msg="Flat and fixed drift result in " "different control pules") H_d = [dript_amps_step[k]*H_0 for k in range(n_ts)] result_step = 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_(result_step.goal_achieved, msg="Step drift goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_step.termination_reason, result_step.fid_err)) # Check step and flat produced different results assert_(np.any( np.abs(result_flat.final_amps - result_step.final_amps) > 1e-3), msg="Flat and step drift result in " "the same control pules")
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)] 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, init_pulse_type='LIN', gen_stats=True) assert_(result.goal_achieved, msg="QFT goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=7, err_msg="QFT infidelity too high") # check bounds result2 = 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_((result2.final_amps >= -1.0).all() and (result2.final_amps <= 1.0).all(), msg="Amplitude bounds exceeded for QFT")
def test_state_to_state(self): """ control.pulseoptim: state-to-state transfer 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 # Run the optimisation result = cpo.optimize_pulse_unitary(H_d, H_c, psi_0, psi_T, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result.goal_achieved, msg="State-to-state goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=10, err_msg="Hadamard infidelity too high") #Try with Qobj propagation result = cpo.optimize_pulse_unitary(H_d, H_c, psi_0, psi_T, 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="State-to-state goal not achieved " "(Qobj propagation)" "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err))
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_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_1_unitary_hadamard(self): """ control.pulseoptim: Hadamard gate with linear initial pulses assert that goal is achieved and fidelity error is below threshold """ # 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 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=True) assert_(result.goal_achieved, msg="Hadamard goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=10, err_msg="Hadamard infidelity too high")
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_02_2_qft_bounds(self): """ 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_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_02_2_qft_bounds(self): """ 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 optimise_and_evaluate_fidelity(target_state_: Qobj, geometry: BaseGeometry): norm_V = C6 / (LATTICE_SPACING**6) / characteristic_V norm_H_d, norm_H_c, psi_0 = get_normalised_hamiltonian(N, norm_V, geometry) result = cpo.optimize_pulse_unitary( norm_H_d, norm_H_c, psi_0, target_state_, n_ts, norm_t, amp_lbound=-3, amp_ubound=3, # pulse_scaling=1, pulse_offset=1, gen_stats=True, alg="GRAPE", init_pulse_type="RND", max_wall_time=30, max_iter=5000, fid_err_targ=1e-3, log_level=qutip.logging_utils.WARN, ) result.stats.report() final_fidelity = qutip.fidelity(target_state_, result.evo_full_final)**2 print(f"Final fidelity: {final_fidelity:.5f}") print(f"Final gradient normal: {result.grad_norm_final:.3e}") print(f"Terminated due to: {result.termination_reason}") return final_fidelity
def get_pulseoptim_results(H_d, H_c, U_targ, alg='CRAB'): # Number of time slots n_ts = 10 # Time allowed for the evolution evo_time = 1 fid_err_targ = 1e-10 # Maximum iterations for the optisation algorithm max_iter = 200 # Maximum (elapsed) time allowed in seconds max_wall_time = 120 # Minimum gradient (sum of gradients squared) # as this tends to 0 -> local minima has been found min_grad = 1e-20 p_type = 'SQUARE' return cpo.optimize_pulse_unitary(H_d, H_c, identity(2), U_targ, n_ts, evo_time, fid_err_targ=fid_err_targ, min_grad=min_grad, max_iter=max_iter, max_wall_time=max_wall_time, out_file_ext=None, init_pulse_type=p_type, alg=alg, log_level=log_level, gen_stats=True)
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)] 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, init_pulse_type='LIN', gen_stats=True) assert_(result.goal_achieved, msg="QFT goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=7, err_msg="QFT infidelity too high") # check bounds result2 = 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_((result2.final_amps >= -1.0).all() and (result2.final_amps <= 1.0).all(), msg="Amplitude bounds exceeded for QFT")
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_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 nu_prop = 0 nu_fwd_evo = 0 nu_onto_evo = 0 for d in dyn.dump.evo_dumps: for k in range(dyn.num_tslots): if not dyn._is_unitary(d.prop[k]): nu_prop += 1 if not dyn._is_unitary(d.fwd_evo[k]): nu_fwd_evo += 1 if not dyn._is_unitary(d.onto_evo[k]): nu_onto_evo += 1 assert_(nu_prop == 0, msg="{} propagators found to be non-unitary".format(nu_prop)) assert_( nu_fwd_evo == 0, msg="{} fwd evo ops found to be non-unitary".format(nu_fwd_evo)) assert_( nu_onto_evo == 0, msg="{} onto evo ops found to be non-unitary".format(nu_onto_evo))
def get_optimised_controls(N: int, n_ts: int, norm_t: float, norm_V: float, target_state_symmetric: bool = True, optim_kwargs: dict = None, ghz_state: BaseGHZState = None, alg="GRAPE") -> OptimResult: norm_H_d, norm_H_c, psi_0 = get_normalised_hamiltonian(N, norm_V) if ghz_state is None: ghz_state = StandardGHZState(N) target_state = ghz_state.get_state_tensor(target_state_symmetric) optim_shared_kwargs = dict( amp_lbound=0, amp_ubound=3, # amp_lbound=0, amp_ubound=2e9 * norm_scaling, gen_stats=True, max_wall_time=300, max_iter=10000, fid_err_targ=1e-10, log_level=qutip.logging_utils.WARN, ) optim_kwargs_ = {**optim_shared_kwargs} if alg == "GRAPE": optim_kwargs_['init_pulse_type'] = "RND" else: optim_kwargs_['guess_pulse_type'] = "RND" optim_kwargs_ = {**optim_kwargs_, **optim_kwargs} if alg == "GRAPE": norm_result = cpo.optimize_pulse_unitary( norm_H_d, norm_H_c, psi_0, target_state, n_ts, norm_t, # pulse_scaling=1e9 * norm_scaling, pulse_offset=1e9 * norm_scaling, # pulse_scaling=0.5, # optim_method="FMIN_BFGS", **optim_kwargs_ ) else: norm_result = cpo.opt_pulse_crab_unitary( norm_H_d, norm_H_c, psi_0, target_state, n_ts, norm_t, # num_coeffs=10, # guess_pulse_scaling=0.1, # guess_pulse_scaling=1e9 * norm_scaling, guess_pulse_offset=1e9 * norm_scaling, **optim_kwargs_ ) return norm_result
def test_05_1_state_to_state(self): """ control.pulseoptim: state-to-state transfer 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 # Run the optimisation result = cpo.optimize_pulse_unitary(H_d, H_c, psi_0, psi_T, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result.goal_achieved, msg="State-to-state goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=10, err_msg="Hadamard infidelity too high")
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 nu_prop = 0 nu_fwd_evo = 0 nu_onto_evo = 0 for d in dyn.dump.evo_dumps: for k in range(dyn.num_tslots): if not dyn._is_unitary(d.prop[k]): nu_prop += 1 if not dyn._is_unitary(d.fwd_evo[k]): nu_fwd_evo += 1 if not dyn._is_unitary(d.onto_evo[k]): nu_onto_evo += 1 assert_(nu_prop==0, msg="{} propagators found to be non-unitary".format(nu_prop)) assert_(nu_fwd_evo==0, msg="{} fwd evo ops found to be non-unitary".format( nu_fwd_evo)) assert_(nu_onto_evo==0, msg="{} onto evo ops found to be non-unitary".format( nu_onto_evo))
def get_optimised_controls(N: int, n_ts: int, alg: str, norm_geometry: BaseGeometry) -> OptimResult: norm_H_d, norm_H_c, psi_0 = get_normalised_hamiltonian(N, norm_geometry) target_state = StandardGHZState(N).get_state_tensor() norm_scaling = 0.5 / characteristic_V optim_shared_kwargs = dict( amp_lbound=AMP_BOUNDS[0], amp_ubound=AMP_BOUNDS[1], # amp_lbound=0, amp_ubound=2e9 * norm_scaling, gen_stats=True, max_wall_time=MAX_WALL_TIME, max_iter=10000000, fid_err_targ=1e-10, log_level=qutip.logging_utils.WARN, ) if alg == "GRAPE": norm_result = cpo.optimize_pulse_unitary( norm_H_d, norm_H_c, psi_0, target_state, n_ts, norm_t, # pulse_scaling=1e9 * norm_scaling, pulse_offset=1e9 * norm_scaling, # pulse_scaling=0.5, # optim_method="FMIN_BFGS", init_pulse_type="RND", **optim_shared_kwargs) else: norm_result = cpo.opt_pulse_crab_unitary( norm_H_d, norm_H_c, psi_0, target_state, n_ts, norm_t, num_coeffs=20, guess_pulse_scaling=0.1, # guess_pulse_scaling=1e9 * norm_scaling, guess_pulse_offset=1e9 * norm_scaling, guess_pulse_type="RND", **optim_shared_kwargs) return norm_result
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, fid_err_targ=1e-10, init_pulse_type='LIN', dyn_params={'oper_dtype': Qobj}, gen_stats=True) assert_(result.goal_achieved, msg="State-to-state goal not achieved " "(Qobj propagation)" "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err))
# Maximum (elapsed) time allowed in seconds max_wall_time = 1600 # Minimum gradient (sum of gradients squared) # as this tends to 0 -> local minima has been found min_grad = 1e-20 p_type = 'CUSTOM' for evo_time in evo_times: n_ts = int(float(evo_time / 0.222)) result = cpo.optimize_pulse_unitary(H0, Hc, U0, u_targ, n_ts, evo_time, amp_lbound=0, amp_ubound=1, fid_err_targ=fid_err_targ, min_grad=min_grad, max_iter=max_iter, max_wall_time=max_wall_time, out_file_ext=None, init_pulse_type=p_type, log_level=log_level, gen_stats=True) result.stats.report() print("Final evolution\n{}\n".format(result.evo_full_final)) print("********* Summary *****************") print("Initial fidelity error {}".format(result.initial_fid_err)) print("Final fidelity error {}".format(result.fid_err)) print("Final gradient normal {}".format(result.grad_norm_final)) print("Terminated due to {}".format(result.termination_reason)) print("Number of iterations {}".format(result.num_iter))
def test_09_load_params(self): """ control.pulseoptim: Hadamard gate (loading config from file) compare with result produced by pulseoptim method """ H_d = sigmaz() H_c = sigmax() U_0 = identity(2) U_targ = hadamard_transform(1) cfg = optimconfig.OptimConfig() cfg.param_fname = "Hadamard_params.ini" cfg.param_fpath = os.path.join(os.path.dirname(__file__), cfg.param_fname) cfg.pulse_type = "ZERO" loadparams.load_parameters(cfg.param_fpath, config=cfg) dyn = dynamics.DynamicsUnitary(cfg) dyn.target = U_targ dyn.initial = U_0 dyn.drift_dyn_gen = H_d dyn.ctrl_dyn_gen = [H_c] loadparams.load_parameters(cfg.param_fpath, dynamics=dyn) dyn.init_timeslots() n_ts = dyn.num_tslots n_ctrls = dyn.num_ctrls pgen = pulsegen.create_pulse_gen(pulse_type=cfg.pulse_type, dyn=dyn) loadparams.load_parameters(cfg.param_fpath, pulsegen=pgen) tc = termcond.TerminationConditions() loadparams.load_parameters(cfg.param_fpath, term_conds=tc) if cfg.optim_method == 'BFGS': optim = optimizer.OptimizerBFGS(cfg, dyn) elif cfg.optim_method == 'FMIN_L_BFGS_B': optim = optimizer.OptimizerLBFGSB(cfg, dyn) elif cfg.optim_method is None: raise errors.UsageError("Optimisation algorithm must be specified " "via 'optim_method' parameter") else: optim = optimizer.Optimizer(cfg, dyn) optim.method = cfg.optim_method loadparams.load_parameters(cfg.param_fpath, optim=optim) sts = stats.Stats() dyn.stats = sts optim.stats = sts optim.config = cfg optim.dynamics = dyn optim.pulse_generator = pgen optim.termination_conditions = tc init_amps = np.zeros([n_ts, n_ctrls]) for j in range(n_ctrls): init_amps[:, j] = pgen.gen_pulse() dyn.initialize_controls(init_amps) result = optim.run_optimization() result2 = cpo.optimize_pulse_unitary(H_d, list([H_c]), U_0, U_targ, 6, 6, fid_err_targ=1e-10, init_pulse_type='LIN', amp_lbound=-1.0, amp_ubound=1.0, gen_stats=True) assert_almost_equal(result.final_amps, result2.final_amps, decimal=5, err_msg="Pulses do not match")
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 # Hadamard H_d = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 1000 evo_time = 4 dump_folder = str(uuid.uuid4()) qtrl_dump_dir = os.path.expanduser(os.path.join('~', dump_folder)) self.tmp_dirs.append(qtrl_dump_dir) optim_dump_dir = os.path.join(qtrl_dump_dir, 'optim') dyn_dump_dir = os.path.join(qtrl_dump_dir, 'dyn') 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', optim_params={'dumping':'FULL', 'dump_to_file':True, 'dump_dir':optim_dump_dir}, dyn_params={'dumping':'FULL', 'dump_to_file':True, 'dump_dir':dyn_dump_dir}, gen_stats=True) # check dumps were generated optim = result.optimizer dyn = optim.dynamics assert_(optim.dump is not None, msg='optimizer dump not created') assert_(dyn.dump is not None, msg='dynamics dump not created') # Count files that were output nfiles = len(os.listdir(optim.dump.dump_dir)) assert_(nfiles == N_EXP_OPTIMDUMP_FILES, msg="{} optimizer dump files generated, {} expected".format( nfiles, N_EXP_OPTIMDUMP_FILES)) nfiles = len(os.listdir(dyn.dump.dump_dir)) assert_(nfiles == N_EXP_DYNDUMP_FILES, msg="{} dynamics dump files generated, {} expected".format( nfiles, N_EXP_DYNDUMP_FILES)) # dump all to specific file stream fpath = os.path.expanduser(os.path.join('~', str(uuid.uuid4()))) self.tmp_files.append(fpath) with open(fpath, 'wb') as f: optim.dump.writeout(f) 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")
def test_12_time_dependent_ctrls(self): """ control.pulseoptim: Hadamard gate with fixed and time varying ctrls assert that goal is achieved for both and that different control pulses are produced (only) when they should be. """ # Hadamard H_0 = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 20 evo_time = 10 # Run the optimisations result_fixed = cpo.optimize_pulse_unitary(H_0, H_c, U_0, U_targ, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result_fixed.goal_achieved, msg="Fixed ctrls goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_fixed.termination_reason, result_fixed.fid_err)) H_c_t = [] for k in range(n_ts): H_c_t.append([sigmax()]) result_tdcs = cpo.optimize_pulse_unitary(H_0, H_c_t, U_0, U_targ, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result_tdcs.goal_achieved, msg="td same ctrl goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_tdcs.termination_reason, result_tdcs.fid_err)) # Check fixed and same produced the same pulse assert_almost_equal(result_fixed.final_amps, result_tdcs.final_amps, decimal=9, err_msg="same and fixed ctrls result in " "different control pules") H_c_t = [] for k in range(n_ts): if k % 3 == 0: H_c_t.append([sigmax()]) else: H_c_t.append([identity(2)]) result_tdcv = cpo.optimize_pulse_unitary(H_0, H_c_t, U_0, U_targ, n_ts, evo_time, fid_err_targ=1e-10, init_pulse_type='LIN', gen_stats=True) assert_(result_tdcv.goal_achieved, msg="true td ctrls goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result_tdcv.termination_reason, result_tdcv.fid_err)) # Check that identity control tslots don't vary for k in range(n_ts): if k % 3 != 0: assert_almost_equal(result_tdcv.initial_amps[k, 0], result_tdcv.final_amps[k, 0], decimal=9, err_msg=("timeslot {} amps should remain " "fixed").format(k))
if __name__ == "__main__": Drift_Hamiltonian, Control_hamiltonian, Initial_unitary, Target_unitary, \ num_timesteps, evolution_time, fidelity_error_required, max_iter, max_wall_time, \ minimum_gradient, p_type = initialize_parameters() # Start timer start_time = time.time() # Run optimization result = cpo.optimize_pulse_unitary(Drift_Hamiltonian, Control_hamiltonian, Initial_unitary, Target_unitary, num_timesteps, evolution_time, fid_err_targ=fidelity_error_required, min_grad=minimum_gradient, max_iter=max_iter, max_wall_time=max_wall_time, init_pulse_type=p_type, log_level=log_level, gen_stats=True) # Output results result.stats.report() print("Final evolution\n{}\n".format(result.evo_full_final)) print(result.termination_reason) print("Optimization duration: " + str(time.time() - start_time) + " seconds") plot = plt.figure()
def test_03_dumping(self): """ control: data dumping Dump out processing data, check file counts """ self.setUp() N_EXP_OPTIMDUMP_FILES = 10 N_EXP_DYNDUMP_FILES = 49 # Hadamard H_d = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 1000 evo_time = 4 dump_folder = str(uuid.uuid4()) qtrl_dump_dir = os.path.expanduser(os.path.join('~', dump_folder)) self.tmp_dirs.append(qtrl_dump_dir) optim_dump_dir = os.path.join(qtrl_dump_dir, 'optim') dyn_dump_dir = os.path.join(qtrl_dump_dir, 'dyn') 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', optim_params={ 'dumping': 'FULL', 'dump_to_file': True, 'dump_dir': optim_dump_dir }, dyn_params={ 'dumping': 'FULL', 'dump_to_file': True, 'dump_dir': dyn_dump_dir }, gen_stats=True) # check dumps were generated optim = result.optimizer dyn = optim.dynamics assert_(optim.dump is not None, msg='optimizer dump not created') assert_(dyn.dump is not None, msg='dynamics dump not created') # Count files that were output nfiles = len(os.listdir(optim.dump.dump_dir)) assert_(nfiles == N_EXP_OPTIMDUMP_FILES, msg="{} optimizer dump files generated, {} expected".format( nfiles, N_EXP_OPTIMDUMP_FILES)) nfiles = len(os.listdir(dyn.dump.dump_dir)) assert_(nfiles == N_EXP_DYNDUMP_FILES, msg="{} dynamics dump files generated, {} expected".format( nfiles, N_EXP_DYNDUMP_FILES)) # dump all to specific file stream fpath = os.path.expanduser(os.path.join('~', str(uuid.uuid4()))) self.tmp_files.append(fpath) with open(fpath, 'wb') as f: optim.dump.writeout(f) 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") self.tearDown()
def test_1_unitary(self): """ control.pulseoptim: Hadamard and QFT gate with linear initial pulses assert that goal is achieved and fidelity error is below threshold """ # 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 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=True) assert_(result.goal_achieved, msg="Hadamard goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=10, err_msg="Hadamard infidelity too high") #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)) #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)) # 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") result2 = optim.run_optimization() assert_almost_equal(result.fid_err, result2.fid_err, decimal=10, err_msg="Direct and indirect methods produce " "different results for Hadamard") # QFT 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) 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', gen_stats=True) assert_(result.goal_achieved, msg="QFT goal not achieved. " "Terminated due to: {}, with infidelity: {}".format( result.termination_reason, result.fid_err)) assert_almost_equal(result.fid_err, 0.0, decimal=7, err_msg="QFT infidelity too high") # check bounds result2 = 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_((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): """ control: data dumping and unitarity checking Dump out processing data and use to check unitary evolution """ N_EXP_OPTIMDUMP_FILES = 10 N_EXP_DYNDUMP_FILES = 49 # Hadamard H_d = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 1000 evo_time = 4 dump_folder = str(uuid.uuid4()) qtrl_dump_dir = os.path.expanduser(os.path.join('~', dump_folder)) self.tmp_dirs.append(qtrl_dump_dir) optim_dump_dir = os.path.join(qtrl_dump_dir, 'optim') dyn_dump_dir = os.path.join(qtrl_dump_dir, 'dyn') 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', optim_params={ 'dumping': 'FULL', 'dump_to_file': True, 'dump_dir': optim_dump_dir }, dyn_params={ 'dumping': 'FULL', 'dump_to_file': True, 'dump_dir': dyn_dump_dir }, gen_stats=True) # check dumps were generated optim = result.optimizer dyn = optim.dynamics assert_(optim.dump is not None, msg='optimizer dump not created') assert_(dyn.dump is not None, msg='dynamics dump not created') # Count files that were output nfiles = len(os.listdir(optim.dump.dump_dir)) assert_(nfiles == N_EXP_OPTIMDUMP_FILES, msg="{} optimizer dump files generated, {} expected".format( nfiles, N_EXP_OPTIMDUMP_FILES)) nfiles = len(os.listdir(dyn.dump.dump_dir)) assert_(nfiles == N_EXP_DYNDUMP_FILES, msg="{} dynamics dump files generated, {} expected".format( nfiles, N_EXP_DYNDUMP_FILES)) # dump all to specific file stream fpath = os.path.expanduser(os.path.join('~', str(uuid.uuid4()))) self.tmp_files.append(fpath) with open(fpath, 'wb') as f: optim.dump.writeout(f) 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") # Use the dump to check unitarity of all propagators and evo_ops dyn.unitarity_tol = 1e-14 nu_prop = 0 nu_fwd_evo = 0 nu_onto_evo = 0 for d in dyn.dump.evo_dumps: for k in range(dyn.num_tslots): if not dyn._is_unitary(d.prop[k]): nu_prop += 1 if not dyn._is_unitary(d.fwd_evo[k]): nu_fwd_evo += 1 if not dyn._is_unitary(d.onto_evo[k]): nu_onto_evo += 1 assert_(nu_prop == 0, msg="{} propagators found to be non-unitary".format(nu_prop)) assert_( nu_fwd_evo == 0, msg="{} fwd evo ops found to be non-unitary".format(nu_fwd_evo)) assert_( nu_onto_evo == 0, msg="{} onto evo ops found to be non-unitary".format(nu_onto_evo))
# Setup N = 1 H_d = sigmaz() H_c = [sigmax()] qc = QubitCircuit(N) qc.add_gate("SNOT", 0) hadamard = qc.propagators()[0] U_targ = hadamard U_0 = identity(U_targ.dims[0]) n_ts = 10 evo_time = 10 # Calculate amps with pulseoptim qtrlresult = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ, n_ts, evo_time) qtrl_amps = qtrlresult.final_amps[:, 0] print("Fidelity error from optimal pulse:", qtrlresult.fid_err) # My way of solving the in consistensy in get_amp: # Modify time and amps a bit, so that it becomes # new_tlist = [ 0, 1, 2, 3, 4, 5, 6...,10,11] # new_amps = [ 0,a0,a1,a2,a3,a4,a5...,a9, 0] tau = int(evo_time / n_ts) # Add a 1.0e-10 to conpensate the unstable round(x.5) new_tlist = np.hstack([qtrlresult.time, [qtrlresult.time[-1] + tau]]) + 1.0e-10 new_amps = np.hstack([[0.], qtrl_amps, [0.]]) # calculate the refined time and amplitude with get_amp dt = 0.001
def test_unitary(self): """ Optimise pulse for Hadamard and QFT gate with linear initial pulses assert that goal is achieved and fidelity error is below threshold """ # Hadamard H_d = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 10 evo_time = 6 # Run the optimisation 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=True) assert_(result.goal_achieved, msg="Hadamard goal not achieved") assert_almost_equal(result.fid_err, 0.0, decimal=10, err_msg="Hadamard infidelity too high") #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)") #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)") # 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") result2 = optim.run_optimization() assert_almost_equal(result.fid_err, result2.fid_err, decimal=10, err_msg="Direct and indirect methods produce " "different results for Hadamard") # QFT 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) 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', gen_stats=True) assert_(result.goal_achieved, msg="QFT goal not achieved") assert_almost_equal(result.fid_err, 0.0, decimal=7, err_msg="QFT infidelity too high") # check bounds result2 = 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_((result2.final_amps >= -1.0).all() and (result2.final_amps <= 1.0).all(), msg="Amplitude bounds exceeded for QFT")
f_ext = "{}_n_ts{}_ptype{}.txt".format(example_name, n_ts, p_type) # Run the optimisation print("\n***********************************") print("Starting pulse optimisation") result = cpo.optimize_pulse_unitary( H_d, H_c, psi_0, psi_T, n_ts, evo_time, fid_err_targ=fid_err_targ, max_iter=max_iter, max_wall_time=max_wall_time, # dyn_params={'oper_dtype':Qobj}, # comment in/out these next three lines for CRAB/GRAPE # alg='CRAB', # alg_params={'init_coeff_scaling':5.0, 'num_coeffs':5, 'guess_pulse_type':None}, # method_params={'xtol':1e-3}, fid_params={'phase_option': 'PSU'}, out_file_ext=f_ext, init_pulse_type=p_type, log_level=log_level, gen_stats=True) print("\n***********************************") print("Optimising complete. Stats follow:") result.stats.report() print("\nFinal evolution\n{}\n".format(result.evo_full_final))
def load_circuit(self, qc, min_fid_err=np.inf, merge_gates=True, setting_args=None, verbose=False, **kwargs): """ Find the pulses realizing a given :class:`qutip.qip.Circuit` using `qutip.control.optimize_pulse_unitary`. Further parameter for for `qutip.control.optimize_pulse_unitary` needs to be given as keyword arguments. By default, it first merge all the gates into one unitary and then find the control pulses for it. It can be turned off and one can set different parameters for different gates. See examples for details. Examples -------- # Same parameter for all the gates qc = QubitCircuit(N=1) qc.add_gate("SNOT", 0) num_tslots = 10 evo_time = 10 processor = OptPulseProcessor(N=1, drift=sigmaz(), ctrls=[sigmax()]) # num_tslots and evo_time are two keyword arguments tlist, coeffs = processor.load_circuit( qc, num_tslots=num_tslots, evo_time=evo_time) # Different parameters for different gates qc = QubitCircuit(N=2) qc.add_gate("SNOT", 0) qc.add_gate("SWAP", targets=[0, 1]) qc.add_gate('CNOT', controls=1, targets=[0]) processor = OptPulseProcessor(N=2, drift=tensor([sigmaz()]*2)) processor.add_ctrl(sigmax(), cyclic_permutation=True) processor.add_ctrl(sigmay(), cyclic_permutation=True) processor.add_ctrl(tensor([sigmay(), sigmay()])) setting_args = {"SNOT": {"num_tslots": 10, "evo_time": 1}, "SWAP": {"num_tslots": 30, "evo_time": 3}, "CNOT": {"num_tslots": 30, "evo_time": 3}} tlist, coeffs = processor.load_circuit(qc, setting_args=setting_args, merge_gates=False) Parameters ---------- qc: :class:`qutip.QubitCircuit` or list of Qobj The quantum circuit to be translated. min_fid_err: float, optional The minimal fidelity tolerance, if the fidelity error of any gate decomposition is higher, a warning will be given. Default is infinite. merge_gates: boolean, optimal If True, merge all gate/Qobj into one Qobj and then find the optimal pulses for this unitary matrix. If False, find the optimal pulses for each gate/Qobj. setting_args: dict, optional Only considered if merge_gates is False. It is a dictionary containing keyword arguments for different gates. E.g: setting_args = {"SNOT": {"num_tslots": 10, "evo_time": 1}, "SWAP": {"num_tslots": 30, "evo_time": 3}, "CNOT": {"num_tslots": 30, "evo_time": 3}} verbose: boolean, optional If true, the information for each decomposed gate will be shown. Default is False. **kwargs keyword arguments for `qutip.control.optimize_pulse_unitary` Returns ------- tlist: array_like A NumPy array specifies the time of each coefficient coeffs: array_like A 2d NumPy array of the shape (len(ctrls), len(tlist)-1). Each row corresponds to the control pulse sequence for one Hamiltonian. Notes ----- len(tlist)-1=coeffs.shape[1] since tlist gives the beginning and the end of the pulses """ if setting_args is None: setting_args = {} if isinstance(qc, QubitCircuit): props = qc.propagators() gates = [g.name for g in qc.gates] elif isinstance(qc, Iterable): props = qc gates = None # using list of Qobj, no gates name else: raise ValueError( "qc should be a " "QubitCircuit or a list of Qobj") if merge_gates: # merge all gates/Qobj into one Qobj props = [gate_sequence_product(props)] gates = None time_record = [] # a list for all the gates coeff_record = [] last_time = 0. # used in concatenation of tlist for prop_ind, U_targ in enumerate(props): U_0 = identity(U_targ.dims[0]) # If qc is a QubitCircuit and setting_args is not empty, # we update the kwargs for each gate. # keyword arguments in setting_arg have priority if gates is not None and setting_args: kwargs.update(setting_args[gates[prop_ind]]) result = cpo.optimize_pulse_unitary( self.drift, self.ctrls, U_0, U_targ, **kwargs) if result.fid_err > min_fid_err: warnings.warn( "The fidelity error of gate {} is higher " "than required limit. Use verbose=True to see" "the more detailed information.".format(prop_ind)) time_record.append(result.time[1:] + last_time) last_time += result.time[-1] coeff_record.append(result.final_amps.T) if verbose: print("********** Gate {} **********".format(prop_ind)) print("Final fidelity error {}".format(result.fid_err)) print("Final gradient normal {}".format( result.grad_norm_final)) print("Terminated due to {}".format(result.termination_reason)) print("Number of iterations {}".format(result.num_iter)) self.tlist = np.hstack([[0.]] + time_record) self.coeffs = np.vstack([np.hstack(coeff_record)]) return self.tlist, self.coeffs
def test_load_params(self): """ Optimise pulse for Hadamard gate by loading config from file compare with result produced by pulseoptim method """ H_d = sigmaz() H_c = sigmax() U_0 = identity(2) U_targ = hadamard_transform(1) cfg = optimconfig.OptimConfig() cfg.param_fname = "Hadamard_params.ini" cfg.param_fpath = os.path.join(os.path.dirname(__file__), cfg.param_fname) cfg.pulse_type = "ZERO" loadparams.load_parameters(cfg.param_fpath, config=cfg) dyn = dynamics.DynamicsUnitary(cfg) dyn.target = U_targ dyn.initial = U_0 dyn.drift_dyn_gen = H_d dyn.ctrl_dyn_gen = [H_c] loadparams.load_parameters(cfg.param_fpath, dynamics=dyn) dyn.init_timeslots() n_ts = dyn.num_tslots n_ctrls = dyn.num_ctrls pgen = pulsegen.create_pulse_gen(pulse_type=cfg.pulse_type, dyn=dyn) loadparams.load_parameters(cfg.param_fpath, pulsegen=pgen) tc = termcond.TerminationConditions() loadparams.load_parameters(cfg.param_fpath, term_conds=tc) if cfg.optim_method == 'BFGS': optim = optimizer.OptimizerBFGS(cfg, dyn) elif cfg.optim_method == 'FMIN_L_BFGS_B': optim = optimizer.OptimizerLBFGSB(cfg, dyn) elif cfg.optim_method is None: raise errors.UsageError("Optimisation algorithm must be specified " "via 'optim_method' parameter") else: optim = optimizer.Optimizer(cfg, dyn) optim.method = cfg.optim_method loadparams.load_parameters(cfg.param_fpath, optim=optim) sts = stats.Stats() dyn.stats = sts optim.stats = sts optim.config = cfg optim.dynamics = dyn optim.pulse_generator = pgen optim.termination_conditions = tc init_amps = np.zeros([n_ts, n_ctrls]) for j in range(n_ctrls): init_amps[:, j] = pgen.gen_pulse() dyn.initialize_controls(init_amps) result = optim.run_optimization() result2 = cpo.optimize_pulse_unitary(H_d, list([H_c]), U_0, U_targ, 6, 6, fid_err_targ=1e-10, init_pulse_type='LIN', amp_lbound=-1.0, amp_ubound=1.0, gen_stats=True) assert_almost_equal(result.final_amps, result2.final_amps, decimal=5, err_msg="Pulses do not match")
def test_dumping_and_unitarity(self): """ control: data dumping and unitarity checking Dump out processing data and use to check unitary evolution """ N_EXP_OPTIMDUMP_FILES = 10 N_EXP_DYNDUMP_FILES = 49 # Hadamard H_d = sigmaz() H_c = [sigmax()] U_0 = identity(2) U_targ = hadamard_transform(1) n_ts = 1000 evo_time = 4 dump_folder = str(uuid.uuid4()) qtrl_dump_dir = os.path.expanduser(os.path.join('~', dump_folder)) self.tmp_dirs.append(qtrl_dump_dir) optim_dump_dir = os.path.join(qtrl_dump_dir, 'optim') dyn_dump_dir = os.path.join(qtrl_dump_dir, 'dyn') 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', optim_params={'dumping':'FULL', 'dump_to_file':True, 'dump_dir':optim_dump_dir}, dyn_params={'dumping':'FULL', 'dump_to_file':True, 'dump_dir':dyn_dump_dir}, gen_stats=True) # check dumps were generated optim = result.optimizer dyn = optim.dynamics assert_(optim.dump is not None, msg='optimizer dump not created') assert_(dyn.dump is not None, msg='dynamics dump not created') # Count files that were output nfiles = len(os.listdir(optim.dump.dump_dir)) assert_(nfiles == N_EXP_OPTIMDUMP_FILES, msg="{} optimizer dump files generated, {} expected".format( nfiles, N_EXP_OPTIMDUMP_FILES)) nfiles = len(os.listdir(dyn.dump.dump_dir)) assert_(nfiles == N_EXP_DYNDUMP_FILES, msg="{} dynamics dump files generated, {} expected".format( nfiles, N_EXP_DYNDUMP_FILES)) # dump all to specific file stream fpath = os.path.expanduser(os.path.join('~', str(uuid.uuid4()))) self.tmp_files.append(fpath) with open(fpath, 'wb') as f: optim.dump.writeout(f) 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") # Use the dump to check unitarity of all propagators and evo_ops dyn.unitarity_tol = 1e-14 nu_prop = 0 nu_fwd_evo = 0 nu_onto_evo = 0 for d in dyn.dump.evo_dumps: for k in range(dyn.num_tslots): if not dyn._is_unitary(d.prop[k]): nu_prop += 1 if not dyn._is_unitary(d.fwd_evo[k]): nu_fwd_evo += 1 if not dyn._is_unitary(d.onto_evo[k]): nu_onto_evo += 1 assert_(nu_prop==0, msg="{} propagators found to be non-unitary".format(nu_prop)) assert_(nu_fwd_evo==0, msg="{} fwd evo ops found to be non-unitary".format( nu_fwd_evo)) assert_(nu_onto_evo==0, msg="{} onto evo ops found to be non-unitary".format( nu_onto_evo))
# pulse type alternatives: RND|ZERO|LIN|SINE|SQUARE|SAW|TRIANGLE| p_type = 'LIN' # ************************************************************* # File extension for output files f_ext = "{}_n_ts{}_ptype{}.txt".format(example_name, n_ts, p_type) # Run the optimisation print("\n***********************************") print("Starting pulse optimisation") result = cpo.optimize_pulse_unitary(H_d, H_c, psi_0, psi_T, n_ts, evo_time, fid_err_targ=fid_err_targ, max_iter=max_iter, max_wall_time=max_wall_time, # dyn_params={'oper_dtype':Qobj}, # comment in/out these next three lines for CRAB/GRAPE # alg='CRAB', # alg_params={'init_coeff_scaling':5.0, 'num_coeffs':5, 'guess_pulse_type':None}, # method_params={'xtol':1e-3}, fid_params={'phase_option':'PSU'}, out_file_ext=f_ext, init_pulse_type=p_type, log_level=log_level, gen_stats=True) print("\n***********************************") print("Optimising complete. Stats follow:") result.stats.report() print("\nFinal evolution\n{}\n".format(result.evo_full_final)) print("********* Summary *****************") print("Initial fidelity error {}".format(result.initial_fid_err)) print("Final fidelity error {}".format(result.fid_err))
# Initial pulse type # pulse type alternatives: RND|ZERO|LIN|SINE|SQUARE|SAW|TRIANGLE| p_type = 'ZERO' # ************************************************************* # File extension for output files f_ext = "{}_n_ts{}_ptype{}.txt".format(example_name, n_ts, p_type) # Run the optimisation print("\n***********************************") print("Starting pulse optimisation") result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ, n_ts, evo_time, fid_err_targ=fid_err_targ, min_grad=min_grad, max_iter=max_iter, max_wall_time=max_wall_time, # dyn_params={'oper_dtype':Qobj}, #phase_option='SU', fid_params={'phase_option':'PSU'}, out_file_ext=f_ext, init_pulse_type=p_type, log_level=log_level, gen_stats=True) print("\n***********************************") print("Optimising complete. Stats follow:") result.stats.report() print("\nFinal evolution\n{}\n".format(result.evo_full_final)) print("********* Summary *****************") print("Initial fidelity error {}".format(result.initial_fid_err)) print("Final fidelity error {}".format(result.fid_err)) print("Final gradient normal {}".format(result.grad_norm_final)) print("Terminated due to {}".format(result.termination_reason)) print("Number of iterations {}".format(result.num_iter))
# *************************** f_ext = "{}_n_ts{}_ptype{}.txt".format(example_name, n_ts, p_type) # Run the optimisation print("\n***********************************") print("Starting pulse optimisation") result = cpo.optimize_pulse_unitary( H_d, ctrls, U_0, U_targ, n_ts, evo_time, fid_err_targ=fid_err_targ, min_grad=min_grad, max_iter=max_iter, max_wall_time=max_wall_time, # dyn_params={'oper_dtype':Qobj}, #phase_option='SU', fid_params={'phase_option': 'PSU'}, out_file_ext=f_ext, init_pulse_type=p_type, log_level=log_level, gen_stats=True) print("\n***********************************") print("Optimising complete. Stats follow:") result.stats.report() print("\nFinal evolution\n{}\n".format(result.evo_full_final)) print("********* Summary *****************")
def run_optimizer(self, unitary, qubit_targets, *args, fid_err_targ=1e-30, max_iter=2000, max_wall_time=120, min_grad=1e-30, alg='GRAPE', zero_wq=True, **kwargs): if self.zero_wq: for i in qubit_targets: self.config.hamiltonian['vars']['wq' + str(i)] = 0 hamiltonian = convert_qutip_ham(self.config, qubit_targets, two_level=self.two_level) drift_hamiltonian = hamiltonian['H_d'] control_hamiltonians = hamiltonian['H_c'] if self.n_ts: n_ts = self.n_ts else: n_ts = 640 if self.two_level: U_0 = Qobj(identity(2**len(qubit_targets)).full()) else: U_0 = Qobj(identity(3**len(qubit_targets)).full()) U_targ = unitary p_type = self.p_type dt = self.dt evo_time = dt * n_ts * 1e9 if self.log_level == 'WARN': log_level = logging.WARN elif self.log_level == 'INFO': log_level = logging.INFO else: log_level = logging.WARN result = optimize_pulse_unitary( drift_hamiltonian, list(control_hamiltonians.values()), U_0, U_targ, n_ts, evo_time, fid_err_targ=fid_err_targ, min_grad=min_grad, max_iter=max_iter, max_wall_time=max_wall_time, out_file_ext=None, init_pulse_type=p_type, log_level=log_level, gen_stats=True, alg=alg, amp_lbound=-0.7, amp_ubound=0.7, phase_option='PSU', optim_method='fmin_l_bfgs_b', method_params={ 'max_metric_corr': 20, 'accuracy_factor': 1e8 }, # dyn_type='UNIT', fid_params={'phase_option': 'PSU'}, *args, **kwargs) amp_dictionary = results_amps_to_dict(result.final_amps, hamiltonian['H_c'].keys()) return amp_dictionary, hamiltonian['H_c'].keys()