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)
Example #3
0
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)
Example #5
0
        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