def test_gate_product(self): filename = "qft.qasm" filepath = Path(__file__).parent / 'qasm_files' / filename qc = read_qasm(filepath) U_list_expanded = qc.propagators() U_list = qc.propagators(expand=False) inds_list = [] for gate in qc.gates: if isinstance(gate, Measurement): continue else: inds_list.append(gate.get_inds(qc.N)) U_1, _ = gate_sequence_product(U_list, inds_list=inds_list, expand=True) U_2 = gate_sequence_product(U_list_expanded, left_to_right=True, expand=False) np.testing.assert_allclose(U_1, U_2)
def test_scheduling_pulse( instructions, method, expected_length, random_shuffle, gates_schedule): circuit = QubitCircuit(4) for instruction in instructions: circuit.add_gate( Gate(instruction.name, instruction.targets, instruction.controls)) if random_shuffle: repeat_num = 5 else: repeat_num = 0 result0 = gate_sequence_product(circuit.propagators()) # run the scheduler scheduler = Scheduler(method) gate_cycle_indices = scheduler.schedule( instructions, gates_schedule=gates_schedule, repeat_num=repeat_num) # check if the scheduled length is expected assert(max(gate_cycle_indices) == expected_length) scheduled_gate = [[] for i in range(max(gate_cycle_indices)+1)] # check if the scheduled circuit is correct for i, cycles in enumerate(gate_cycle_indices): scheduled_gate[cycles].append(circuit.gates[i]) circuit.gates = sum(scheduled_gate, []) result1 = gate_sequence_product(circuit.propagators()) assert(tracedist(result0*result1.dag(), qeye(result0.dims[0])) < 1.0e-7)
def testresolve(self, gate_from, gate_to, targets, controls): qc1 = QubitCircuit(2) qc1.add_gate(gate_from, targets=targets, controls=controls) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates(basis=gate_to) U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def test_device_against_gate_sequence(num_qubits, gates, device_class, kwargs): circuit = qutip.qip.circuit.QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) U_ideal = gate_sequence_product(circuit.propagators()) device = device_class(num_qubits, correct_global_phase=True) U_physical = gate_sequence_product(device.run(circuit)) assert (U_ideal - U_physical).norm() < _tol
def test_device_against_gate_sequence(gates): n_qubits = 3 circuit = qutip.qip.circuit.QubitCircuit(n_qubits) for gate in gates: circuit.add_gate(gate) U_ideal = gate_sequence_product(circuit.propagators()) device = DispersiveCavityQED(n_qubits, correct_global_phase=True) U_physical = gate_sequence_product(device.run(circuit)) assert (U_ideal - U_physical).norm() < _tol
def testFREDKINdecompose(self): """ FREDKIN to rotation and CNOT: compare unitary matrix for FREDKIN and product of resolved matrices in terms of rotation gates and CNOT. """ qc1 = QubitCircuit(3) qc1.add_gate("FREDKIN", targets=[0, 1], controls=[2]) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates() U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def test_analytical_evolution(num_qubits, gates, device_class, kwargs): circuit = qutip.qip.circuit.QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] ideal = gate_sequence_product([state] + circuit.propagators()) device = device_class(num_qubits, correct_global_phase=True) operators = device.run_state(init_state=state, qc=circuit, analytical=True) result = gate_sequence_product(operators) assert abs(qutip.metrics.fidelity(result, ideal) - 1) < _tol
def testSNOTdecompose(self): """ SNOT to rotation: compare unitary matrix for SNOT and product of resolved matrices in terms of rotation gates. """ qc1 = QubitCircuit(1) qc1.add_gate("SNOT", targets=0) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates() U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def testISWAPtoCNOT(self): """ ISWAP to CNOT: compare unitary matrix for ISWAP and product of resolved matrices in terms of CNOT. """ qc1 = QubitCircuit(2) qc1.add_gate("ISWAP", targets=[0, 1]) U1 = gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates(basis="CNOT") U2 = gate_sequence_product(qc2.propagators()) assert_((U1 - U2).norm() < 1e-12)
def testCNOTtoCSIGN(self): """ CNOT to CSIGN: compare unitary matrix for CNOT and product of resolved matrices in terms of CSIGN. """ qc1 = QubitCircuit(2) qc1.add_gate("CNOT", targets=[0], controls=[1]) U1 = gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates(basis="CSIGN") U2 = gate_sequence_product(qc2.propagators()) assert_((U1 - U2).norm() < 1e-12)
def test_analytical_evolution(): n_qubits = 3 circuit = qutip.qip.circuit.QubitCircuit(n_qubits) for gate in [_iswap, _rz, _rx]: circuit.add_gate(gate) state = qutip.rand_ket(2**n_qubits) state.dims = [[2] * n_qubits, [1] * n_qubits] ideal = gate_sequence_product([state] + circuit.propagators()) device = DispersiveCavityQED(n_qubits, correct_global_phase=True) operators = device.run_state(init_state=state, qc=circuit, analytical=True) result = gate_sequence_product(operators) assert abs(qutip.metrics.fidelity(result, ideal) - 1) < _tol
def testadjacentgates(self): """ Adjacent Gates: compare unitary matrix for ISWAP and product of resolved matrices in terms of adjacent gates interaction. """ qc1 = QubitCircuit(3) qc1.add_gate("ISWAP", targets=[0, 2]) U1 = gates.gate_sequence_product(qc1.propagators()) qc0 = qc1.adjacent_gates() qc2 = qc0.resolve_gates(basis="ISWAP") U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def test_numerical_evolution(num_qubits, gates, device_class, kwargs): num_qubits = 3 circuit = qutip.qip.circuit.QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) with warnings.catch_warnings(record=True): device = device_class(num_qubits, **kwargs) device.load_circuit(circuit) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] target = gate_sequence_product([state] + circuit.propagators()) if len(device.dims) > num_qubits: num_ancilla = len(device.dims) - num_qubits ancilla_indices = slice(0, num_ancilla) extra = qutip.basis(device.dims[ancilla_indices], [0] * num_ancilla) init_state = qutip.tensor(extra, state) else: init_state = state options = qutip.Options(store_final_state=True, nsteps=50_000) result = device.run_state(init_state=init_state, analytical=False, options=options) if len(device.dims) > num_qubits: target = qutip.tensor(extra, target) assert _tol > abs(1 - qutip.metrics.fidelity(result.final_state, target))
def test_linear_SQRTISWAP(self): """ Linear Spin Chain Setup: compare unitary matrix for SQRTISWAP and propogator matrix of the implemented physical model. """ N = 3 qc = QubitCircuit(N) qc.add_gate("SQRTISWAP", targets=[0, 1]) U_ideal = gate_sequence_product(qc.propagators()) p = LinearSpinChain(N, correct_global_phase=True) U_list = p.run(qc) U_physical = gate_sequence_product(U_list) assert_((U_ideal - U_physical).norm() < 1e-12)
def testQFTComparison(self): """ qft: compare qft and product of qft steps """ for N in range(1, 5): U1 = qft(N) U2 = gate_sequence_product(qft_steps(N)) assert_((U1 - U2).norm() < 1e-12)
def test_numerical_evo(self): """ Test run_state with qutip solver """ N = 3 qc = QubitCircuit(N) qc.add_gate("RX", targets=[0], arg_value=np.pi / 2) qc.add_gate("CNOT", targets=[0], controls=[1]) qc.add_gate("ISWAP", targets=[2, 1]) qc.add_gate("CNOT", targets=[0], controls=[2]) qc.add_gate("SQRTISWAP", targets=[0, 2]) qc.add_gate("RZ", arg_value=np.pi / 2, targets=[1]) # CircularSpinChain test = CircularSpinChain(N) tlist, coeffs = test.load_circuit(qc) init_state = rand_ket(2**N) init_state.dims = [[2] * N, [1] * N] rho1 = gate_sequence_product([init_state] + qc.propagators()) result = test.run_state( init_state=init_state, analytical=False, options=Options(store_final_state=True)).final_state assert_allclose( fidelity(result, rho1), 1., rtol=1e-6, err_msg="Numerical run_state fails in CircularSpinChain") # LinearSpinChain test = LinearSpinChain(N) tlist, coeffs = test.load_circuit(qc) init_state = rand_ket(2**N) init_state.dims = [[2] * N, [1] * N] rho1 = gate_sequence_product([init_state] + qc.propagators()) result = test.run_state( init_state=init_state, analytical=False, options=Options(store_final_state=True)).final_state assert_allclose(fidelity(result, rho1), 1., rtol=1e-6, err_msg="Numerical run_state fails in LinearSpinChain")
def test_linear_combination(self): """ Linear Spin Chain Setup: compare unitary matrix for ISWAP, SQRTISWAP, RX and RY gates and the propogator matrix of the implemented physical model. """ N = 3 qc = QubitCircuit(N) qc.add_gate("ISWAP", targets=[0, 1]) qc.add_gate("SQRTISWAP", targets=[0, 1]) qc.add_gate("RZ", arg_value=np.pi / 2, arg_label=r"\pi/2", targets=[1]) qc.add_gate("RX", arg_value=np.pi / 2, arg_label=r"\pi/2", targets=[0]) U_ideal = gate_sequence_product(qc.propagators()) p = LinearSpinChain(N, correct_global_phase=True) U_list = p.run(qc) U_physical = gate_sequence_product(U_list) assert_((U_ideal - U_physical).norm() < 1e-12)
def hst_measurement(state: Qobj, qcircuit, sample_size=1): """Hilbert-Schmidt test""" N = len(state.dims[0]) qc = QubitCircuit(N * 2) qc.add_circuit(qcircuit) if state.isket: statein = tensor(state, qubit_states(N)) elif state.isbra: statein = tensor(state, qubit_states(N).dag()) elif state.isoper: statein = tensor(state, ket2dm(qubit_states(N))) state_preps = statein.transform( gate_sequence_product(bell_prep(N, True).propagators())) state_out = state_preps.transform(gate_sequence_product(qc.propagators())) state_postps = state_out.transform( gate_sequence_product(bell_prep(N).propagators())) prob = com_measure(state_postps) hst = np.random.choice(4**N, sample_size, p=prob) mresult = [ state_index_number(state_postps.dims[0], result) for result in hst ] return mresult # raw output
def dst_measurement(state1, state2, sample_size=1): """destructive swap test""" N = len(state1.dims[0]) if len(state2.dims[0]) != N: raise ValueError("Dimensions of states dismatch.") statein = tensor(state1, state2) stateout = statein.transform( gate_sequence_product(bell_prep(N, True).propagators())) prob = com_measure(stateout) result_in_number = np.random.choice(4**N, sample_size, p=prob) mresult = [ state_index_number(stateout.dims[0], result) for result in result_in_number ] return mresult # raw output
def test_numerical_evolution(): n_qubits = 3 circuit = qutip.qip.circuit.QubitCircuit(n_qubits) circuit.add_gate("RX", targets=[0], arg_value=np.pi / 2) circuit.add_gate("CNOT", targets=[0], controls=[1]) circuit.add_gate("ISWAP", targets=[2, 1]) circuit.add_gate("CNOT", targets=[0], controls=[2]) with warnings.catch_warnings(record=True): device = DispersiveCavityQED(n_qubits, g=0.1) device.load_circuit(circuit) state = qutip.rand_ket(2**n_qubits) state.dims = [[2] * n_qubits, [1] * n_qubits] target = gate_sequence_product([state] + circuit.propagators()) extra = qutip.basis(10, 0) options = qutip.Options(store_final_state=True, nsteps=50_000) result = device.run_state(init_state=qutip.tensor(extra, state), analytical=False, options=options) assert _tol > abs(1 - qutip.metrics.fidelity(result.final_state, qutip.tensor(extra, target)))
def test_numerical_circuit(circuit, device_class, kwargs, schedule_mode): num_qubits = circuit.N device = device_class(circuit.N, **kwargs) device.load_circuit(circuit, schedule_mode=schedule_mode) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] target = gate_sequence_product([state] + circuit.propagators()) if len(device.dims) > num_qubits: num_ancilla = len(device.dims) - num_qubits ancilla_indices = slice(0, num_ancilla) extra = qutip.basis(device.dims[ancilla_indices], [0] * num_ancilla) init_state = qutip.tensor(extra, state) else: init_state = state options = qutip.Options(store_final_state=True, nsteps=50_000) result = device.run_state(init_state=init_state, analytical=False, options=options) if len(device.dims) > num_qubits: target = qutip.tensor(extra, target) assert _tol > abs(1 - qutip.metrics.fidelity(result.final_state, target))
def test_multi_gates(self): N = 2 H_d = tensor([sigmaz()] * 2) H_c = [] test = OptPulseProcessor(N) test.add_drift(H_d, [0, 1]) test.add_control(sigmax(), cyclic_permutation=True) test.add_control(sigmay(), cyclic_permutation=True) test.add_control(tensor([sigmay(), sigmay()])) # qubits circuit with 3 gates setting_args = { "SNOT": { "num_tslots": 10, "evo_time": 1 }, "SWAP": { "num_tslots": 30, "evo_time": 3 }, "CNOT": { "num_tslots": 30, "evo_time": 3 } } qc = QubitCircuit(N) qc.add_gate("SNOT", 0) qc.add_gate("SWAP", targets=[0, 1]) qc.add_gate('CNOT', controls=1, targets=[0]) test.load_circuit(qc, setting_args=setting_args, merge_gates=False) rho0 = rand_ket(4) # use random generated ket state rho0.dims = [[2, 2], [1, 1]] U = gate_sequence_product(qc.propagators()) rho1 = U * rho0 result = test.run_state(rho0) assert_(fidelity(result.states[-1], rho1) > 1 - 1.0e-6)
def grape_unitary_adaptive(U, H0, H_ops, R, times, eps=None, u_start=None, u_limits=None, interp_kind='linear', use_interp=False, alpha=None, beta=None, phase_sensitive=False, overlap_terminate=1.0, progress_bar=BaseProgressBar()): """ Calculate control pulses for the Hamiltonian operators in H_ops so that the unitary U is realized. Experimental: Work in progress. Parameters ---------- U : Qobj Target unitary evolution operator. H0 : Qobj Static Hamiltonian (that cannot be tuned by the control fields). H_ops: list of Qobj A list of operators that can be tuned in the Hamiltonian via the control fields. R : int Number of GRAPE iterations. time : array / list Array of time coordinates for control pulse evalutation. u_start : array Optional array with initial control pulse values. Returns ------- Instance of GRAPEResult, which contains the control pulses calculated with GRAPE, a time-dependent Hamiltonian that is defined by the control pulses, as well as the resulting propagator. """ if eps is None: eps = 0.1 * (2 * np.pi) / (times[-1]) eps_vec = np.array([eps / 2, eps, 2 * eps]) eps_log = np.zeros(R) overlap_log = np.zeros(R) best_k = 0 _k_overlap = np.array([0.0, 0.0, 0.0]) M = len(times) J = len(H_ops) K = len(eps_vec) Uf = [None for _ in range(K)] u = np.zeros((R, J, M, K)) if u_limits and len(u_limits) != 2: raise ValueError("u_limits must be a list with two values") if u_limits: warnings.warn("Causion: Using experimental feature u_limits") if u_limits and u_start: # make sure that no values in u0 violates the u_limits conditions u_start = np.array(u_start) u_start[u_start < u_limits[0]] = u_limits[0] u_start[u_start > u_limits[1]] = u_limits[1] if u_start is not None: for idx, u0 in enumerate(u_start): for k in range(K): u[0, idx, :, k] = u0 if beta: warnings.warn("Causion: Using experimental feature time-penalty") if phase_sensitive: _fidelity_function = lambda x: x else: _fidelity_function = lambda x: abs(x) ** 2 best_k = 1 _r = 0 _prev_overlap = 0 progress_bar.start(R) for r in range(R - 1): progress_bar.update(r) _r = r eps_log[r] = eps_vec[best_k] logger.debug("eps_vec: {}".format(eps_vec)) _t0 = time.time() dt = times[1] - times[0] if use_interp: ip_funcs = [interp1d(times, u[r, j, :, best_k], kind=interp_kind, bounds_error=False, fill_value=u[r, j, -1, best_k]) for j in range(J)] def _H_t(t, args=None): return H0 + sum([float(ip_funcs[j](t)) * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_t(times[idx]) * dt).expm() for idx in range(M-1)] else: def _H_idx(idx): return H0 + sum([u[r, j, idx, best_k] * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_idx(idx) * dt).expm() for idx in range(M-1)] logger.debug("Time 1: %fs" % (time.time() - _t0)) _t0 = time.time() U_f_list = [] U_b_list = [] U_f = 1 U_b = 1 for m in range(M - 1): U_f = U_list[m] * U_f U_f_list.append(U_f) U_b_list.insert(0, U_b) U_b = U_list[M - 2 - m].dag() * U_b logger.debug("Time 2: %fs" % (time.time() - _t0)) _t0 = time.time() for j in range(J): for m in range(M-1): P = U_b_list[m] * U Q = 1j * dt * H_ops[j] * U_f_list[m] if phase_sensitive: du = - cy_overlap(P.data, Q.data) else: du = (- 2 * cy_overlap(P.data, Q.data) * cy_overlap(U_f_list[m].data, P.data)) if alpha: # penalty term for high power control signals u du += -2 * alpha * u[r, j, m, best_k] * dt if beta: # penalty term for late control signals u du += -2 * beta * k ** 2 * u[r, j, k] * dt for k, eps_val in enumerate(eps_vec): u[r + 1, j, m, k] = u[r, j, m, k] + eps_val * du.real if u_limits: if u[r + 1, j, m, k] < u_limits[0]: u[r + 1, j, m, k] = u_limits[0] elif u[r + 1, j, m, k] > u_limits[1]: u[r + 1, j, m, k] = u_limits[1] u[r + 1, j, -1, :] = u[r + 1, j, -2, :] logger.debug("Time 3: %fs" % (time.time() - _t0)) _t0 = time.time() for k, eps_val in enumerate(eps_vec): def _H_idx(idx): return H0 + sum([u[r + 1, j, idx, k] * H_ops[j] for j in range(J)]) U_list = [(-1j * _H_idx(idx) * dt).expm() for idx in range(M-1)] Uf[k] = gate_sequence_product(U_list) _k_overlap[k] = _fidelity_function(cy_overlap(Uf[k].data, U.data)).real best_k = np.argmax(_k_overlap) logger.debug("k_overlap: ", _k_overlap, best_k) if _prev_overlap > _k_overlap[best_k]: logger.debug("Regression, stepping back with smaller eps.") u[r + 1, :, :, :] = u[r, :, :, :] eps_vec /= 2 else: if best_k == 0: eps_vec /= 2 elif best_k == 2: eps_vec *= 2 _prev_overlap = _k_overlap[best_k] overlap_log[r] = _k_overlap[best_k] if overlap_terminate < 1.0: if _k_overlap[best_k] > overlap_terminate: logger.info("Reached target fidelity, terminating.") break logger.debug("Time 4: %fs" % (time.time() - _t0)) _t0 = time.time() if use_interp: ip_funcs = [interp1d(times, u[_r, j, :, best_k], kind=interp_kind, bounds_error=False, fill_value=u[R - 1, j, -1]) for j in range(J)] H_td_func = [H0] + [[H_ops[j], lambda t, args, j=j: ip_funcs[j](t)] for j in range(J)] else: H_td_func = [H0] + [[H_ops[j], u[_r, j, :, best_k]] for j in range(J)] progress_bar.finished() result = GRAPEResult(u=u[:_r, :, :, best_k], U_f=Uf[best_k], H_t=H_td_func) result.eps = eps_log result.overlap = overlap_log return result
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_control(sigmax(), cyclic_permutation=True) processor.add_control(sigmay(), cyclic_permutation=True) processor.add_control(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]]) full_drift_ham = self.drift.get_ideal_qobjevo(self.dims).cte full_ctrls_hams = [pulse.get_ideal_qobj(self.dims) for pulse in self.pulses] result = cpo.optimize_pulse_unitary( full_drift_ham, full_ctrls_hams, 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)) tlist = np.hstack([[0.]] + time_record) for i in range(len(self.pulses)): self.pulses[i].tlist = tlist coeffs = np.vstack([np.hstack(coeff_record)]) self.coeffs = coeffs return tlist, coeffs