Esempio n. 1
0
def test_biased_noise_representation_with_choi(
    gate: Gate, epsilon: float, eta: float
):
    """Tests the representation by comparing exact Choi matrices."""
    qreg = LineQubit.range(gate.num_qubits())
    ideal_choi = _operation_to_choi(gate.on(*qreg))
    op_rep = represent_operation_with_local_biased_noise(
        Circuit(gate.on(*qreg)), epsilon, eta
    )
    choi_components = []

    # Define biased noise channel
    a = 1 - epsilon
    b = epsilon * (3 * eta + 1) / (3 * (eta + 1))
    c = epsilon / (3 * (eta + 1))

    mix = [
        (a, unitary(I)),
        (b, unitary(Z)),
        (c, unitary(X)),
        (c, unitary(Y)),
    ]

    for noisy_op, coeff in op_rep.basis_expansion.items():
        implementable_circ = noisy_op.circuit()
        # Apply noise after each sequence.
        # NOTE: noise is not applied after each operation.
        biased_op = ops.MixedUnitaryChannel(mix).on_each(*qreg)
        implementable_circ.append(biased_op)
        sequence_choi = _circuit_to_choi(implementable_circ)
        choi_components.append(coeff * sequence_choi)
    combination_choi = np.sum(choi_components, axis=0)
    assert np.allclose(ideal_choi, combination_choi, atol=10**-6)
Esempio n. 2
0
def test_amplitude_damping_representation_with_choi(
    gate: Gate,
    noise: float,
    circuit_type: str,
):
    """Tests the representation by comparing exact Choi matrices."""
    q = LineQubit(0)
    ideal_circuit = convert_from_mitiq(Circuit(gate.on(q)), circuit_type)
    ideal_choi = _circuit_to_choi(Circuit(gate.on(q)))
    op_rep = _represent_operation_with_amplitude_damping_noise(
        ideal_circuit,
        noise,
    )
    choi_components = []
    for noisy_op, coeff in op_rep.basis_expansion.items():
        implementable_circ = noisy_op.circuit()
        depolarizing_op = AmplitudeDampingChannel(noise).on(q)
        # Apply noise after each sequence.
        # NOTE: noise is not applied after each operation.
        implementable_circ.append(depolarizing_op)
        sequence_choi = _operation_to_choi(implementable_circ)
        choi_components.append(coeff * sequence_choi)

    combination_choi = np.sum(choi_components, axis=0)
    assert np.allclose(ideal_choi, combination_choi, atol=10**-8)
Esempio n. 3
0
def test_single_qubit_gates(qasm_gate: str, cirq_gate: cirq.Gate):
    qasm = """OPENQASM 2.0;
     include "qelib1.inc";
     qreg q[2];
     {0} q[0];
     {0} q;
    """.format(qasm_gate)

    parser = QasmParser()

    q0 = cirq.NamedQubit('q_0')
    q1 = cirq.NamedQubit('q_1')

    expected_circuit = Circuit(
        [cirq_gate.on(q0),
         cirq_gate.on(q0),
         cirq_gate.on(q1)])

    parsed_qasm = parser.parse(qasm)

    assert parsed_qasm.supportedFormat
    assert parsed_qasm.qelib1Include

    ct.assert_same_circuits(parsed_qasm.circuit, expected_circuit)
    assert parsed_qasm.qregs == {'q': 2}
Esempio n. 4
0
def test_get_imp_sequences_no_simplify(gate: Gate):
    q = LineQubit(0)
    expected_imp_sequences = [
        [gate.on(q)],
        [gate.on(q), X.on(q)],
        [gate.on(q), Y.on(q)],
        [gate.on(q), Z.on(q)],
    ]
    assert get_imp_sequences(gate.on(q), DECO_DICT) == expected_imp_sequences
Esempio n. 5
0
def test_simplify_paulis_in_simple_pauli_deco_dict(gate: Gate):
    """Tests DECO_DICT_SIMP which is initialized using the 'simplify_paulis'
    option. This should produce decomposition dictionary in which Pauli
    sequences are simplified to single Pauli gates.
    """
    qreg = LineQubit.range(2)
    decomposition_dict = DECO_DICT_SIMP
    for q in qreg:
        deco = decomposition_dict[gate.on(q)]
        _, first_imp_seq = deco[0]
        assert first_imp_seq == [gate.on(q)]
        _, second_imp_seq = deco[1]
        input_times_x = {X: I, Y: Z, Z: Y}
        assert second_imp_seq == [input_times_x[gate].on(q)]
Esempio n. 6
0
def test_simple_pauli_deco_dict_with_Choi(gate: Gate):
    """Tests the decomposition by comparing the exact Choi matrices."""
    qreg = LineQubit.range(gate.num_qubits())
    ideal_choi = _operation_to_choi(gate.on(*qreg))
    op_decomp = DECO_DICT[gate.on(*qreg)]
    choi_components = []
    for coeff, imp_seq in op_decomp:
        # Apply noise after each sequence.
        # NOTE: noise is not applied after each operation.
        noisy_sequence = [imp_seq] + [depolarize(BASE_NOISE)(q) for q in qreg]
        sequence_choi = _operation_to_choi(noisy_sequence)
        choi_components.append(coeff * sequence_choi)
    combination_choi = np.sum(choi_components, axis=0)
    assert np.allclose(ideal_choi, combination_choi)
Esempio n. 7
0
def test_sample_sequence_choi(gate: cirq.Gate):
    """Tests the sample_sequence by comparing the exact Choi matrices."""
    qreg = cirq.LineQubit.range(gate.num_qubits())
    ideal_op = gate.on(*qreg)
    ideal_circ = cirq.Circuit(ideal_op)
    noisy_op_tree = [ideal_op] + [cirq.depolarize(BASE_NOISE)(q) for q in qreg]

    ideal_choi = _operation_to_choi(ideal_op)
    noisy_choi = _operation_to_choi(noisy_op_tree)

    representation = represent_operation_with_local_depolarizing_noise(
        ideal_circ,
        BASE_NOISE,
    )

    choi_unbiased_estimates = []
    rng = np.random.RandomState(1)
    for _ in range(500):
        imp_seqs, signs, norm = sample_sequence(ideal_circ, [representation],
                                                random_state=rng)
        noisy_sequence = imp_seqs[0].with_noise(cirq.depolarize(BASE_NOISE))
        sequence_choi = _circuit_to_choi(noisy_sequence)
        choi_unbiased_estimates.append(norm * signs[0] * sequence_choi)

    choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0)
    noise_error = np.linalg.norm(ideal_choi - noisy_choi)
    pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate)

    assert pec_error < noise_error
    assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)
Esempio n. 8
0
def test_get_coefficients(gate: Gate):
    q = LineQubit(0)
    coeffs = get_coefficients(gate.on(q), DECO_DICT)
    epsilon = BASE_NOISE * 4.0 / 3.0
    c_neg = -(1 / 4) * epsilon / (1 - epsilon)
    c_pos = 1 - 3 * c_neg
    assert np.isclose(np.sum(coeffs), 1.0)
    assert np.allclose(coeffs, [c_pos, c_neg, c_neg, c_neg])
Esempio n. 9
0
def test_sample_sequence_types(gate: Gate):
    num_qubits = gate.num_qubits()
    qreg = LineQubit.range(num_qubits)
    for _ in range(1000):
        imp_seq, sign, norm = sample_sequence(gate.on(*qreg), DECO_DICT)
        assert all([isinstance(op, Operation) for op in imp_seq])
        assert sign in {1, -1}
        assert norm > 1
Esempio n. 10
0
def test_depolarizing_representation_with_choi(gate: Gate, noise: float):
    """Tests the representation by comparing exact Choi matrices."""
    qreg = LineQubit.range(gate.num_qubits())
    ideal_choi = _operation_to_choi(gate.on(*qreg))
    op_rep = represent_operation_with_global_depolarizing_noise(
        Circuit(gate.on(*qreg)), noise,
    )
    choi_components = []
    for noisy_op, coeff in op_rep.basis_expansion.items():
        implementable_circ = noisy_op.circuit()
        # Apply noise after each sequence.
        # NOTE: noise is not applied after each operation.
        depolarizing_op = DepolarizingChannel(noise, len(qreg))(*qreg)
        implementable_circ.append(depolarizing_op)
        sequence_choi = _circuit_to_choi(implementable_circ)
        choi_components.append(coeff * sequence_choi)
    combination_choi = np.sum(choi_components, axis=0)
    assert np.allclose(ideal_choi, combination_choi, atol=10 ** -6)
Esempio n. 11
0
def test_simple_pauli_deco_dict_single_qubit(gate: Gate):
    """Tests that the _simple_pauli_deco_dict function returns a decomposition
    dicitonary which is consistent with a local depolarizing noise model.

    This is similar to test_simple_pauli_deco_dict_CNOT but applied to
    single-qubit gates.
    """
    epsilon = BASE_NOISE * 4.0 / 3.0
    c_neg = -(1 / 4) * epsilon / (1 - epsilon)
    c_pos = 1 - 3 * c_neg
    qreg = LineQubit.range(2)
    for q in qreg:
        deco = DECO_DICT[gate.on(q)]
        first_coefficient, first_imp_seq = deco[0]
        assert np.isclose(c_pos, first_coefficient)
        assert first_imp_seq == [gate.on(q)]
        second_coefficient, second_imp_seq = deco[1]
        assert np.isclose(c_neg, second_coefficient)
        assert second_imp_seq == [gate.on(q), X.on(q)]
Esempio n. 12
0
def test_sample_sequence_choi(gate: Gate):
    """Tests the sample_sequence by comparing the exact Choi matrices."""
    qreg = LineQubit.range(gate.num_qubits())
    ideal_op = gate.on(*qreg)
    noisy_op_tree = [ideal_op] + [depolarize(BASE_NOISE)(q) for q in qreg]
    ideal_choi = _operation_to_choi(gate.on(*qreg))
    noisy_choi = _operation_to_choi(noisy_op_tree)
    choi_unbiased_estimates = []
    for _ in range(500):
        imp_seq, sign, norm = sample_sequence(gate.on(*qreg), DECO_DICT)
        # Apply noise after each sequence.
        # NOTE: noise is not applied after each operation.
        noisy_sequence = [imp_seq] + [depolarize(BASE_NOISE)(q) for q in qreg]
        sequence_choi = _operation_to_choi(noisy_sequence)
        choi_unbiased_estimates.append(norm * sign * sequence_choi)
    choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0)
    noise_error = np.linalg.norm(ideal_choi - noisy_choi)
    pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate)
    assert pec_error < noise_error
    assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)
Esempio n. 13
0
def test_gate_decomposition(gate: cirq.Gate,
                            testcase: unittest.TestCase,
                            print_circuit=True,
                            expected_unitary=None):
    qubits = cirq.LineQubit.range(2)
    control, target = qubits
    circuit_compressed = cirq.Circuit()
    circuit_decomposed = cirq.Circuit()

    circuit_compressed.append(gate.on(control, target))
    circuit_decomposed.append(
        cirq.decompose(gate.on(control, target), keep=is_a_basic_operation))

    if print_circuit:
        print("Compressed circuit: \n{}".format(circuit_compressed))
        print("Decomposed circuit: \n{}".format(circuit_decomposed))

        print(cirq.unitary(circuit_compressed).round(3))
        print(cirq.unitary(circuit_decomposed).round(3))

    testcase.assertTrue(
        np.allclose((cirq.unitary(circuit_compressed)
                     if expected_unitary is None else expected_unitary),
                    cirq.unitary(circuit_decomposed)))
Esempio n. 14
0
def random_cliffords(
    connectivity_graph: nx.Graph,
    random_state: random.RandomState,
    two_qubit_gate: cirq.Gate = cirq.CNOT,
) -> cirq.Circuit:
    """Returns a circuit with a two-qubit Clifford gate applied
    to each edge in edges, and a random single-qubit
    Clifford gate applied to every other qubit.

    Args:
        connectivity_graph: A graph with the edges for which the
            two-qubit Clifford gate is to be applied.
        random_state: Random state to choose Cliffords (uniformly at random).
        two_qubit_gate: Two-qubit gate to use.
    """
    gates = [
        two_qubit_gate.on(cirq.LineQubit(a), cirq.LineQubit(b))
        for a, b in list(connectivity_graph.edges)
    ]
    qubits = nx.Graph()
    qubits.add_nodes_from(nx.isolates(connectivity_graph))
    gates.extend(
        list(random_single_cliffords(qubits, random_state).all_operations()))
    return cirq.Circuit(gates)
Esempio n. 15
0
def add_hadamard_test(state: typing.Union[cirq.Qid, typing.Iterable[cirq.Qid]],
                      gate_v: cirq.Gate, gate_a: cirq.Gate,
                      is_imaginary_part: bool, circuit: cirq.Circuit) -> str:
    """
    Add an Hadamard test for `state` |ψ0> to estimate <ψ0|V+ A V|ψ0>,
    the circuit of which is:

    999: ───H─────S/I─────@──────H──────M('Hadamard test measure 0')───
                          │
    0: ─────V─────────────A────────────────────────────────────────────

    where S/I is set to be the identity gate / the Clifford S gate when
    `is_imaginary_part` is False / True (i.e. when estimating the real /
    imaginary part of <ψ0|V+ A V|ψ0>).

    :param state:
        The input state |ψ0>.
    :param gate_v:
    :param gate_a:
    :param is_imaginary_part:
    :param circuit:
    :return:
    """
    if isinstance(state, cirq.Qid):
        state = [state]

    if gate_a.num_qubits() == gate_v.num_qubits() == len(state):
        pass
    else:
        raise ValueError(
            "The number of qubits acted on by gate `V` and `A` must equal to "
            "that of `state`, but they are found to be {}, {} and {}.".format(
                gate_v.num_qubits(), gate_a.num_qubits(), len(state)))

    auxiliary_qubit = generate_auxiliary_qubit(circuit)

    measurement_name = "Hadamard test measure "

    existed_hadamard_measurement_ids = {
        int(key[len(measurement_name):])
        for key in get_all_measurement_keys(circuit)
        if key.startswith(measurement_name)
    }
    hadamard_measurement_id = (max(existed_hadamard_measurement_ids) +
                               1 if len(existed_hadamard_measurement_ids) != 0
                               else 0)
    measurement_name += str(hadamard_measurement_id)

    circuit.append([cirq.H(auxiliary_qubit), gate_v.on(*state)])

    if is_imaginary_part is False:
        pass
    else:
        circuit.append(cirq.S(auxiliary_qubit))

    circuit.append([cirq.ControlledGate(gate_a).on(auxiliary_qubit, *state)])

    circuit.append(cirq.H(auxiliary_qubit))
    circuit.append(cirq.measure(auxiliary_qubit, key=measurement_name))

    return measurement_name
Esempio n. 16
0
def test_get_one_norm(gate: Gate):
    q = LineQubit(0)
    epsilon = BASE_NOISE * 4.0 / 3.0
    expected_one_norm = (1.0 + 0.5 * epsilon) / (1.0 - epsilon)
    assert np.isclose(get_one_norm(gate.on(q), DECO_DICT), expected_one_norm)
Esempio n. 17
0
def test_get_probabilities(gate: Gate):
    q = LineQubit(0)
    probs = get_probabilities(gate.on(q), DECO_DICT)
    assert all([p >= 0 for p in probs])
    assert np.isclose(sum(probs), 1.0)