def test_channel_average_gate_fidelity(self): """Test the average_gate_fidelity function for channel inputs""" depol = Choi(np.eye(4) / 2) iden = Choi(Operator.from_label('I')) # Completely depolarizing channel f_ave = average_gate_fidelity(depol, require_cp=True, require_tp=True) self.assertAlmostEqual(f_ave, 0.5, places=7) # Identity f_ave = average_gate_fidelity(iden, require_cp=True, require_tp=True) self.assertAlmostEqual(f_ave, 1.0, places=7) # Depolarizing channel prob = 0.11 chan = prob * depol + (1 - prob) * iden f_ave = average_gate_fidelity(chan, require_cp=True, require_tp=True) f_target = (2 * (prob * 0.25 + (1 - prob)) + 1) / 3 self.assertAlmostEqual(f_ave, f_target, places=7) # Depolarizing channel prob = 0.5 op = Operator.from_label('Y') chan = (prob * depol + (1 - prob) * iden) @ op f_ave = average_gate_fidelity(chan, op, require_cp=True, require_tp=True) target = (2 * (prob * 0.25 + (1 - prob)) + 1) / 3 self.assertAlmostEqual(f_ave, target, places=7)
def test_operator_average_gate_fidelity(self): """Test the average_gate_fidelity function for operator inputs""" # Orthogonal operator op = Operator.from_label('Z') f_ave = average_gate_fidelity(op, require_cp=True, require_tp=True) self.assertAlmostEqual(f_ave, 1 / 3, places=7) # Global phase operator op1 = Operator.from_label('Y') op2 = -1j * op1 f_ave = average_gate_fidelity(op1, op2, require_cp=True, require_tp=True) self.assertAlmostEqual(f_ave, 1.0, places=7)
def _device_depolarizing_error(qubits, error_param, relax_error=None, standard_gates=True, warnings=True): """Construct a depolarizing_error for device""" # We now deduce the depolarizing channel error parameter in the # presence of T1/T2 thermal relaxation. We assume the gate error # parameter is given by e = 1 - F where F is the average gate fidelity, # and that this average gate fidelity is for the composition # of a T1/T2 thermal relaxation channel and a depolarizing channel. # For the n-qubit depolarizing channel E_dep = (1-p) * I + p * D, where # I is the identity channel and D is the completely depolarizing # channel. To compose the errors we solve for the equation # F = F(E_dep * E_relax) # = (1 - p) * F(I * E_relax) + p * F(D * E_relax) # = (1 - p) * F(E_relax) + p * F(D) # = F(E_relax) - p * (dim * F(E_relax) - 1) / dim # Hence we have that the depolarizing error probability # for the composed depolarization channel is # p = dim * (F(E_relax) - F) / (dim * F(E_relax) - 1) if relax_error is not None: relax_fid = qi.average_gate_fidelity(relax_error) relax_infid = 1 - relax_fid else: relax_fid = 1 relax_infid = 0 if error_param is not None and error_param > relax_infid: num_qubits = len(qubits) dim = 2**num_qubits error_max = dim / (dim + 1) # Check if reported error param is un-physical # The minimum average gate fidelity is F_min = 1 / (dim + 1) # So the maximum gate error is 1 - F_min = dim / (dim + 1) if error_param > error_max: if warnings: logger.warning( 'Device reported a gate error parameter greater' ' than maximum allowed value (%f > %f). Truncating to' ' maximum value.', error_param, error_max) error_param = error_max # Model gate error entirely as depolarizing error num_qubits = len(qubits) dim = 2**num_qubits depol_param = dim * (error_param - relax_infid) / (dim * relax_fid - 1) max_param = 4**num_qubits / (4**num_qubits - 1) if depol_param > max_param: if warnings: logger.warning( 'Device model returned a depolarizing error parameter greater' ' than maximum allowed value (%f > %f). Truncating to' ' maximum value.', depol_param, max_param) depol_param = min(depol_param, max_param) return depolarizing_error(depol_param, num_qubits, standard_gates=standard_gates) return None
def test_channel_gate_error(self): """Test the gate_error function for channel inputs""" depol = Choi(np.eye(4) / 2) iden = Choi(Operator.from_label('I')) # Depolarizing channel prob = 0.11 chan = prob * depol + (1 - prob) * iden err = gate_error(chan, require_cp=True, require_tp=True) target = 1 - average_gate_fidelity(chan) self.assertAlmostEqual(err, target, places=7) # Depolarizing channel prob = 0.5 op = Operator.from_label('Y') chan = (prob * depol + (1 - prob) * iden) @ op err = gate_error(chan, op, require_cp=True, require_tp=True) target = 1 - average_gate_fidelity(chan, op) self.assertAlmostEqual(err, target, places=7)
for i in range(len(L)): if L[i].pulse_type == 'noise': pulse_noise.append(L[i]) m = np.identity(2) for i in reversed(range(len(pulse_noise))): m = pulse_to_unitary( pulse_noise[i], delta / 2) @ m # delta/2: 1/2 here because of Clifford decomposition noise_unitary.append(m) depol_str = [] for i in range(len(noise_unitary)): ch = quantum_info.Operator(noise_unitary[i]) F_ave = quantum_info.average_gate_fidelity(ch) p = (d * F_ave - 1) / (d - 1) depol_str.append(p) avg_depol_str.append(np.mean(depol_str)) depha_m = np.cos(delta) * I_1q - 1j * np.sin(delta) * Z_1q depha_ch = quantum_info.Operator(depha_m) F_depha = quantum_info.average_gate_fidelity(depha_ch) p_depha = (d * F_depha - 1) / (d - 1) depha_str.append(p_depha) plot1 = plt.figure(1) plt.plot(delta_list, depha_str, 'ro', markersize=2, label='channel noise') plt.plot(delta_list, avg_depol_str, 'bo',
def hamiltonian_reconstruction(channels: List[Choi], pauli_labels: List[str], gate_time: float, phase_shifts: List[float] = None, shifter_label: str = 'ZI', sanity_check: bool = False)\ -> Tuple[Dict[str, np.ndarray], List[float]]: """ Extract Pauli term coefficient from quantum channel. Args: channels: quantum channels to reconstruct Hamiltonian. pauli_labels: name of Pauli terms gate_time: duration of gate phase_shifts: phase shift to unwrap 2pi uncertainty. shifter_label: pauli term to shift. sanity_check: do sanity check. Additional information: To remove 2pi uncertainty of Logm, we need decompose superop S to satisfy |M| < 2 pi. S_H = exp(w * L_H) where L_H is superop of Pauli term shift. According to BCH expansion:: M = logm(S. S_H) = logm(exp(tG).exp(w L_H)) = tG + w L_H + t*w*[G, L_H] + O(2 coms) M' = M - w L_H Then Pauli coefficients are:: b = Tr[B^dag.M'] = t*Tr[B^dag.G] + t*w*Tr[B^dag.[G, L_H]] + O(2 coms) = b_true + + t*w*Tr[B^dag.[G, L_H]] + O(2 coms) When commutator of G and L_H is zero, b = b_true. Optimizer finds w to calculate principal matrix log. """ threshold_san1 = 1e-3 threshold_san2 = 1e-1 def hamiltonian_superop(ham): ham = qi.Operator(ham) dim, _ = ham.dim iden = np.eye(dim) super_op = -1j * np.kron(iden, ham.data) + 1j * np.kron( np.conj(ham.data), iden) return qi.SuperOp(super_op) if phase_shifts is None: phase_shifts = [0 for _ in range(len(channels))] coeffs = defaultdict(list) estimated_hamiltonian_fidelities = [] for phase_shift, chan in zip(phase_shifts, channels): sup_s = qi.SuperOp(chan) sup_l_h = hamiltonian_superop(qi.Operator.from_label(shifter_label)) def logm(w): sup_s_h = qi.SuperOp(la.expm(w * sup_l_h.data)) return la.logm((sup_s @ sup_s_h).data) def cost_func(w): gen_m = logm(w) - w * sup_l_h.data target = qi.SuperOp(la.expm(gen_m)) if __HAS_DNORM: return dnorm(sup_s - target) # use 2-norm when old version qiskit is used. both cost functions perform comparably. return la.norm(sup_s.data - target.data) def log_constraint(w): return 2 * np.pi - la.norm(logm(w)) cons = ({'type': 'ineq', 'fun': log_constraint}) opt_result = opt.minimize(cost_func, x0=phase_shift, constraints=cons, method='SLSQP') w_opt = opt_result.x[0] # opt status print('w_opt = %.3e, cost_func = %.3e, generator norm = %.3e' % (w_opt, cost_func(w_opt), log_constraint(w_opt))) # sanitary check 1 sup_s_h_opt = qi.SuperOp(la.expm(w_opt * sup_l_h.data)) com_norm = la.norm((sup_s @ sup_s_h_opt - sup_s_h_opt @ sup_s).data) print('Commutator [S, S_H] norm = %.3e' % com_norm) if sanity_check: assert com_norm < threshold_san1 gen_m_opt = logm(w_opt) - w_opt * sup_l_h.data for pauli_label in pauli_labels: sup_b = hamiltonian_superop( 0.5 * qi.Operator.from_label(pauli_label).data) sup_b_dag = sup_b.adjoint() renorm = np.real(np.trace((sup_b_dag @ sup_b).data)) coeff = np.real( np.trace(np.dot(gen_m_opt, sup_b_dag.data)) / renorm) coeffs[pauli_label].append(coeff / gate_time) # sanitary check 2 reconst_ham = np.zeros((4, 4)) for pauli_label in pauli_labels: ham_op = 0.5 * qi.Operator.from_label(pauli_label).data reconst_ham = reconst_ham + coeffs[pauli_label][-1] * ham_op reconst_u = qi.Operator(la.expm(-1j * reconst_ham * gate_time)) u_fid = qi.average_gate_fidelity(chan, reconst_u) estimated_hamiltonian_fidelities.append(u_fid) if sanity_check: assert 1 - u_fid < threshold_san2 # list -> ndarray coeffs = dict(coeffs) for pauli_label in coeffs.keys(): coeffs[pauli_label] = np.array(coeffs[pauli_label]) return coeffs, estimated_hamiltonian_fidelities