Example #1
0
def assert_unitary_gate_converts_correctly(gate: cirq.Gate):
    n = gate.num_qubits()
    for pre, post in solve_tableau(gate).items():
        # Create a circuit that measures pre before the gate times post after the gate.
        # If the gate is translated correctly, the measurement will always be zero.

        c = stim.Circuit()
        c.append_operation("H", range(n))
        for i in range(n):
            c.append_operation("CNOT", [i, i + n])
        c.append_operation("H", [2 * n])
        for q, p in pre.items():
            c.append_operation(f"C{p}", [2 * n, q.x])
        qs = cirq.LineQubit.range(n)
        conv_gate, _ = cirq_circuit_to_stim_data(cirq.Circuit(gate(*qs)),
                                                 q2i={q: q.x
                                                      for q in qs})
        c += conv_gate
        for q, p in post.items():
            c.append_operation(f"C{p}", [2 * n, q.x])
        if post.coefficient == -1:
            c.append_operation("Z", [2 * n])
        c.append_operation("H", [2 * n])
        c.append_operation("M", [2 * n])
        correct = not np.any(c.compile_sampler().sample_bit_packed(10))
        assert correct, f"{gate!r} failed to turn {pre} into {post}.\nConverted to:\n{conv_gate}\n"
Example #2
0
def test_noisy_gate_conversions_compiled_sampler(gate: cirq.Gate):
    # Create test circuit that uses superdense coding to quantify arbitrary Pauli error mixtures.
    n = gate.num_qubits()
    qs = cirq.LineQubit.range(n)
    circuit = cirq.Circuit(
        cirq.H.on_each(qs),
        [cirq.CNOT(q, q + n) for q in qs],
        gate(*qs),
        [cirq.CNOT(q, q + n) for q in qs],
        cirq.H.on_each(qs),
    )
    expected_rates = cirq.final_density_matrix(circuit).diagonal().real

    # Convert test circuit to Stim and sample from it.
    stim_circuit, _ = cirq_circuit_to_stim_data(circuit + cirq.measure(
        *sorted(circuit.all_qubits())[::-1]))
    sample_count = 10000
    samples = stim_circuit.compile_sampler().sample_bit_packed(
        sample_count).flat
    unique, counts = np.unique(samples, return_counts=True)

    # Compare sample rates to expected rates.
    for value, count in zip(unique, counts):
        expected_rate = expected_rates[value]
        actual_rate = count / sample_count
        allowed_variation = 5 * (expected_rate *
                                 (1 - expected_rate) / sample_count)**0.5
        if not 0 <= expected_rate - allowed_variation <= 1:
            raise ValueError(
                "Not enough samples to bound results away from extremes.")
        assert abs(expected_rate - actual_rate) < allowed_variation, (
            f"Sample rate {actual_rate} is over 5 standard deviations away from {expected_rate}.\n"
            f"Gate: {gate}\n"
            f"Test circuit:\n{circuit}\n"
            f"Converted circuit:\n{stim_circuit}\n")
Example #3
0
def test_more_unitary_gate_conversions():
    for p in [1, 1j, -1, -1j]:
        assert_unitary_gate_converts_correctly(p *
                                               cirq.DensePauliString("IXYZ"))
        assert_unitary_gate_converts_correctly(
            (p * cirq.DensePauliString("IXYZ")).controlled(1))

    a, b = cirq.LineQubit.range(2)
    c, _ = cirq_circuit_to_stim_data(
        cirq.Circuit(cirq.H(a), cirq.CNOT(a, b), cirq.measure(a, b),
                     cirq.reset(a)))
    assert (str(c).strip() == """
H 0
CX 0 1
M 0 1
R 0
    """.strip())
Example #4
0
def test_tableau_simulator_error_mechanisms(gate: cirq.Gate):
    # Technically this be a test of the `stim` package itself, but it's so convenient to compare to cirq.

    # Create test circuit that uses superdense coding to quantify arbitrary Pauli error mixtures.
    n = gate.num_qubits()
    qs = cirq.LineQubit.range(n)
    circuit = cirq.Circuit(
        cirq.H.on_each(qs),
        [cirq.CNOT(q, q + n) for q in qs],
        gate(*qs),
        [cirq.CNOT(q, q + n) for q in qs],
        cirq.H.on_each(qs),
    )
    expected_rates = cirq.final_density_matrix(circuit).diagonal().real

    # Convert test circuit to Stim and sample from it.
    stim_circuit, _ = cirq_circuit_to_stim_data(circuit + cirq.measure(
        *sorted(circuit.all_qubits())[::-1]))
    sample_count = 10000
    samples = []
    for _ in range(sample_count):
        sim = stim.TableauSimulator()
        sim.do(stim_circuit)
        s = 0
        for k, v in enumerate(sim.current_measurement_record()):
            s |= v << k
        samples.append(s)

    unique, counts = np.unique(samples, return_counts=True)

    # Compare sample rates to expected rates.
    for value, count in zip(unique, counts):
        expected_rate = expected_rates[value]
        actual_rate = count / sample_count
        allowed_variation = 5 * (expected_rate *
                                 (1 - expected_rate) / sample_count)**0.5
        if not 0 <= expected_rate - allowed_variation <= 1:
            raise ValueError(
                "Not enough samples to bound results away from extremes.")
        assert abs(expected_rate - actual_rate) < allowed_variation, (
            f"Sample rate {actual_rate} is over 5 standard deviations away from {expected_rate}.\n"
            f"Gate: {gate}\n"
            f"Test circuit:\n{circuit}\n"
            f"Converted circuit:\n{stim_circuit}\n")