Пример #1
0
def test_clifford_state_str():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})

    assert str(state) == "|00⟩"
Пример #2
0
def test_clifford_state_state_vector():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})

    np.testing.assert_equal(state.state_vector(),
                            [1.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j])
Пример #3
0
def direct_fidelity_estimation(circuit: cirq.Circuit, qubits: List[cirq.Qid],
                               sampler: cirq.Sampler,
                               n_measured_operators: Optional[int],
                               samples_per_term: int):
    """
    Implementation of direct fidelity estimation, as per 'Direct Fidelity
    Estimation from Few Pauli Measurements' https://arxiv.org/abs/1104.4695 and
    'Practical characterization of quantum devices without tomography'
    https://arxiv.org/abs/1104.3835.

    Args:
        circuit: The circuit to run the simulation on.
        qubits: The list of qubits.
        sampler: Either a noisy simulator or an engine.
        n_measured_operators: The total number of Pauli measurements, or None to
            explore each Pauli state once.
        samples_per_term: if set to 0, we use the 'sampler' parameter above as
            a noise (must be of type cirq.DensityMatrixSimulator) and
            simulate noise in the circuit. If greater than 0, we instead use the
            'sampler' parameter directly to estimate the characteristic
            function.
    Returns:
        The estimated fidelity and a log of the run.
    """
    # n_measured_operators is upper-case N in https://arxiv.org/abs/1104.3835

    # Number of qubits, lower-case n in https://arxiv.org/abs/1104.3835
    n_qubits = len(qubits)

    clifford_circuit = True
    clifford_state: Optional[cirq.CliffordState] = None
    try:
        clifford_state = cirq.CliffordState(
            qubit_map={qubits[i]: i
                       for i in range(len(qubits))})
        for gate in circuit.all_operations():
            clifford_state.apply_unitary(gate)
    except ValueError:
        clifford_circuit = False

    # Computes for every \hat{P_i} of https://arxiv.org/abs/1104.3835
    # estimate rho_i and Pr(i). We then collect tuples (rho_i, Pr(i), \hat{Pi})
    # inside the variable 'pauli_traces'.
    if clifford_circuit:
        assert clifford_state is not None
        pauli_traces = _estimate_pauli_traces_clifford(
            n_qubits, cast(cirq.CliffordState, clifford_state),
            n_measured_operators)
    else:
        pauli_traces = _estimate_pauli_traces_general(qubits, circuit,
                                                      n_measured_operators)

    p = np.asarray([x.Pr_i for x in pauli_traces])

    if n_measured_operators is None:
        # Since we enumerate all the possible traces, the probs should add to 1.
        assert np.isclose(np.sum(p), 1.0, atol=1e-6)
    p /= np.sum(p)

    fidelity = 0.0

    if samples_per_term == 0:
        # sigma in https://arxiv.org/abs/1104.3835
        if not isinstance(sampler, cirq.DensityMatrixSimulator):
            raise TypeError('sampler is not a cirq.DensityMatrixSimulator '
                            'but samples_per_term is zero.')
        noisy_simulator = cast(cirq.DensityMatrixSimulator, sampler)
        noisy_density_matrix = cast(
            cirq.DensityMatrixTrialResult,
            noisy_simulator.simulate(circuit)).final_density_matrix

    if clifford_circuit and n_measured_operators is None:
        # In case the circuit is Clifford and we compute an exhaustive list of
        # Pauli traces, instead of sampling we can simply enumerate them because
        # they all have the same probability.
        measured_pauli_traces = pauli_traces
    else:
        # Otherwise, randomly sample as per probability.
        measured_pauli_traces = np.random.choice(pauli_traces,
                                                 size=len(pauli_traces),
                                                 p=p)

    trial_results: List[TrialResult] = []
    for pauli_trace in measured_pauli_traces:
        measure_pauli_string: cirq.PauliString = pauli_trace.P_i
        rho_i = pauli_trace.rho_i

        if samples_per_term > 0:
            sigma_i = asyncio.get_event_loop().run_until_complete(
                estimate_characteristic_function(circuit, measure_pauli_string,
                                                 qubits, sampler,
                                                 samples_per_term))
        else:
            sigma_i, _ = compute_characteristic_function(
                circuit, measure_pauli_string, qubits, noisy_density_matrix)

        trial_results.append(
            TrialResult(pauli_trace=pauli_trace, sigma_i=sigma_i))

        fidelity += sigma_i / rho_i

    estimated_fidelity = fidelity / len(pauli_traces)

    std_dev_estimate: Optional[float]
    std_dev_bound: Optional[float]
    if clifford_circuit:
        std_dev_estimate, std_dev_bound = _estimate_std_devs_clifford(
            estimated_fidelity, len(measured_pauli_traces))
    else:
        std_dev_estimate, std_dev_bound = None, None

    dfe_intermediate_result = DFEIntermediateResult(
        clifford_state=clifford_state,
        pauli_traces=pauli_traces,
        trial_results=trial_results,
        std_dev_estimate=std_dev_estimate,
        std_dev_bound=std_dev_bound)

    return estimated_fidelity, dfe_intermediate_result
Пример #4
0
def test_clifford_state_initial_state():
    q0 = cirq.LineQubit(0)
    with pytest.raises(ValueError, match='Out of range'):
        _ = cirq.CliffordState(qubit_map={q0: 0}, initial_state=2)
    state = cirq.CliffordState(qubit_map={q0: 0}, initial_state=1)
    np.testing.assert_allclose(state.state_vector(), [0, 1])
Пример #5
0
def test_stabilizerStateChForm_H():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})
    with pytest.raises(ValueError, match="|y> is equal to |z>"):
        state.ch_form._H_decompose(0, 1, 1, 0)
Пример #6
0
def test_clifford_stabilizerStateChForm_repr():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})
    assert repr(state) == 'StabilizerStateChForm(num_qubits=2)'
Пример #7
0
def test_clifford_tableau_repr():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})
    f = cirq.DensePauliString
    assert (repr(state.tableau) == "stabilizers: [{!r}, {!r}]".format(
        f("ZI"), f("IZ")))
Пример #8
0
def test_clifford_state_wave_function():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})

    np.testing.assert_equal(state.wave_function(),
                            [1. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j])
def direct_fidelity_estimation(circuit: cirq.Circuit, qubits: List[cirq.Qid],
                               sampler: cirq.Sampler, n_trials: int,
                               n_clifford_trials: int, samples_per_term: int):
    """
    Implementation of direct fidelity estimation, as per 'Direct Fidelity
    Estimation from Few Pauli Measurements' https://arxiv.org/abs/1104.4695 and
    'Practical characterization of quantum devices without tomography'
    https://arxiv.org/abs/1104.3835.

    Args:
        circuit: The circuit to run the simulation on.
        qubits: The list of qubits.
        sampler: Either a noisy simulator or an engine.
        n_trial: The total number of Pauli measurements.
        n_clifford_trials: In case the circuit is Clifford, we specify the
            number of trials to estimate the noise-free pauli traces.
        samples_per_term: if set to 0, we use the 'sampler' parameter above as
            a noise (must be of type cirq.DensityMatrixSimulator) and
            simulate noise in the circuit. If greater than 0, we instead use the
            'sampler' parameter directly to estimate the characteristic
            function.
    Returns:
        The estimated fidelity.
    """
    # n_trials is upper-case N in https://arxiv.org/abs/1104.3835

    # Number of qubits, lower-case n in https://arxiv.org/abs/1104.3835
    n_qubits = len(qubits)
    d = 2**n_qubits

    clifford_circuit = True
    clifford_state: Optional[cirq.CliffordState] = None
    try:
        clifford_state = cirq.CliffordState(
            qubit_map={qubits[i]: i
                       for i in range(len(qubits))})
        for gate in circuit.all_operations():
            clifford_state.apply_unitary(gate)
    except ValueError:
        clifford_circuit = False

    # Computes for every \hat{P_i} of https://arxiv.org/abs/1104.3835
    # estimate rho_i and Pr(i). We then collect tuples (rho_i, Pr(i), \hat{Pi})
    # inside the variable 'pauli_traces'.
    if clifford_circuit:
        print('Circuit is Clifford')
        assert clifford_state is not None
        pauli_traces = _estimate_pauli_traces_clifford(
            n_qubits, cast(cirq.CliffordState, clifford_state),
            n_clifford_trials)
    else:
        print('Circuit is not Clifford')
        pauli_traces = _estimate_pauli_traces_general(qubits, circuit)

    p = np.asarray([x['Pr_i'] for x in pauli_traces])

    if not clifford_circuit:
        # For Clifford circuits, we do a Monte Carlo simulations, and thus there
        # is no guarantee that it adds up to 1.0 (but it should to the limit).
        assert np.isclose(np.sum(p), 1.0, atol=1e-6)

    # The package np.random.choice() is quite sensitive to probabilities not
    # summing up to 1.0. Even an absolute difference below 1e-6 (as checked just
    # above) does bother it, so we re-normalize the probs.
    p /= np.sum(p)

    fidelity = 0.0

    if samples_per_term == 0:
        # sigma in https://arxiv.org/abs/1104.3835
        if not isinstance(sampler, cirq.DensityMatrixSimulator):
            raise TypeError('sampler is not a cirq.DensityMatrixSimulator '
                            'but samples_per_term is zero.')
        noisy_simulator = cast(cirq.DensityMatrixSimulator, sampler)
        noisy_density_matrix = cast(
            cirq.DensityMatrixTrialResult,
            noisy_simulator.simulate(circuit)).final_density_matrix

    for _ in range(n_trials):
        # Randomly sample as per probability.
        i = np.random.choice(len(pauli_traces), p=p)

        Pr_i = pauli_traces[i]['Pr_i']
        measure_pauli_string: cirq.PauliString = pauli_traces[i]['P_i']
        rho_i = pauli_traces[i]['rho_i']

        if samples_per_term > 0:
            sigma_i = asyncio.get_event_loop().run_until_complete(
                estimate_characteristic_function(circuit, measure_pauli_string,
                                                 qubits, sampler,
                                                 samples_per_term))
        else:
            sigma_i, _ = compute_characteristic_function(
                circuit, measure_pauli_string, qubits, noisy_density_matrix)

        fidelity += Pr_i * sigma_i / rho_i

    return fidelity / n_trials * d
Пример #10
0
def test_valid_apply_measurement():
    q0 = cirq.LineQubit(0)
    state = cirq.CliffordState(qubit_map={q0: 0}, initial_state=1)
    measurements = {}
    _ = state.apply_measurement(cirq.measure(q0), measurements, np.random.RandomState())
    assert measurements == {'0': [1]}
Пример #11
0
def test_clifford_tableau_repr():
    (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1))
    state = cirq.CliffordState(qubit_map={q0: 0, q1: 1})

    assert (repr(state.tableau) == "stabilizers: [Z0, Z1]")