Beispiel #1
0
def test_controlled_op_to_gates_omits_negligible_global_phase():
    qc = ops.QubitId()
    qt = ops.QubitId()
    operations = decompositions.controlled_op_to_native_gates(
        control=qc, target=qt, operation=ops.H.matrix(), tolerance=0.0001)

    assert operations == [ops.Y(qt)**-0.25, ops.CZ(qc, qt), ops.Y(qt)**0.25]
Beispiel #2
0
def _with_parameterized_layers(
    circuit: 'cirq.Circuit',
    qubits: Sequence['cirq.Qid'],
    needs_init_layer: bool,
) -> 'cirq.Circuit':
    """Return a copy of the input circuit with parameterized single-qubit rotations.

    These rotations flank the circuit: the initial two layers of X and Y gates
    are given parameter names "{qubit}-Xi" and "{qubit}-Yi" and are used
    to set up the initial state. If `needs_init_layer` is False,
    these two layers of gates are omitted.

    The final two layers of X and Y gates are given parameter names
    "{qubit}-Xf" and "{qubit}-Yf" and are use to change the frame of the
    qubit before measurement, effectively measuring in bases other than Z.
    """
    x_beg_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xi') for q in qubits])
    y_beg_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yi') for q in qubits])
    x_end_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xf') for q in qubits])
    y_end_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yf') for q in qubits])
    meas_mom = ops.Moment([ops.measure(*qubits, key='z')])
    if needs_init_layer:
        total_circuit = circuits.Circuit([x_beg_mom, y_beg_mom])
        total_circuit += circuit.copy()
    else:
        total_circuit = circuit.copy()
    total_circuit.append([x_end_mom, y_end_mom, meas_mom])
    return total_circuit
Beispiel #3
0
def nonoptimal_toffoli_circuit(q0: 'cirq.Qid', q1: 'cirq.Qid',
                               q2: 'cirq.Qid') -> circuits.Circuit:
    ret = circuits.Circuit(
        ops.Y(q2)**0.5,
        ops.X(q2),
        ops.CNOT(q1, q2),
        ops.Z(q2)**-0.25,
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q0, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.Z(q2)**0.25,
        ops.CNOT(q1, q2),
        ops.Z(q2)**-0.25,
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q0, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.Z(q2)**0.25,
        ops.Z(q1)**0.25,
        ops.CNOT(q0, q1),
        ops.Z(q0)**0.25,
        ops.Z(q1)**-0.25,
        ops.CNOT(q0, q1),
        ops.Y(q2)**0.5,
        ops.X(q2),
    )
    return ret
def known_two_q_operations_to_sycamore_operations(
    qubit_a: ops.Qid,
    qubit_b: ops.Qid,
    op: ops.Operation,
    tabulation: Optional[GateTabulation] = None,
) -> ops.OP_TREE:
    """
    Synthesize a known gate operation to a sycamore operation

    This function dispatches based on gate type

    Args:
        qubit_a: first qubit of GateOperation
        qubit_b: second qubit of GateOperation
        op: operation to decompose
        tabulation: A tabulation for the Sycamore gate to use for
            decomposing gates.
    Returns:
        New operations iterable object
    """
    gate = op.gate
    if isinstance(gate, ops.PhasedISwapPowGate):
        if math.isclose(gate.exponent, 1):
            return decompose_phased_iswap_into_syc(gate.phase_exponent,
                                                   qubit_a, qubit_b)
        elif math.isclose(gate.phase_exponent, 0.25):
            return decompose_phased_iswap_into_syc_precomputed(
                gate.exponent * np.pi / 2, qubit_a, qubit_b)
        else:
            raise ValueError(
                "To decompose PhasedISwapPowGate, it must have a phase_exponent"
                " of .25 OR an exponent of 1.0, but got: {!r}".format(op))
    if isinstance(gate, ops.CNotPowGate):
        return [
            ops.Y(qubit_b)**-0.5,
            cphase(gate.exponent * np.pi, qubit_a, qubit_b),
            ops.Y(qubit_b)**0.5,
        ]
    elif isinstance(gate, ops.CZPowGate):
        if math.isclose(gate.exponent, 1):  # check if CZ or CPHASE
            return decompose_cz_into_syc(qubit_a, qubit_b)
        else:
            # because CZPowGate == diag([1, 1, 1, e^{i pi phi}])
            return cphase(gate.exponent * np.pi, qubit_a, qubit_b)
    elif isinstance(gate, ops.SwapPowGate) and math.isclose(gate.exponent, 1):
        return decompose_swap_into_syc(qubit_a, qubit_b)
    elif isinstance(gate, ops.ISwapPowGate) and math.isclose(gate.exponent, 1):
        return decompose_iswap_into_syc(qubit_a, qubit_b)
    elif isinstance(gate, ops.ZZPowGate):
        return rzz(gate.exponent * np.pi / 2, *op.qubits)
    elif protocols.unitary(gate, None) is not None:
        if tabulation:
            return decompose_arbitrary_into_syc_tabulation(
                qubit_a, qubit_b, op, tabulation)
        else:
            return decompose_arbitrary_into_syc_analytic(qubit_a, qubit_b, op)
    else:
        raise ValueError("Unrecognized gate: {!r}".format(op))
Beispiel #5
0
 def _decompose_(self, qubits):
     from cirq import ops
     a, b = qubits
     return [
         ops.GlobalPhaseOperation(self.global_phase),
         ops.MatrixGate(self.single_qubit_operations_before[0]).on(a),
         ops.MatrixGate(self.single_qubit_operations_before[1]).on(b),
         np.exp(1j * ops.X(a) * ops.X(b) * self.interaction_coefficients[0]),
         np.exp(1j * ops.Y(a) * ops.Y(b) * self.interaction_coefficients[1]),
         np.exp(1j * ops.Z(a) * ops.Z(b) * self.interaction_coefficients[2]),
         ops.MatrixGate(self.single_qubit_operations_after[0]).on(a),
         ops.MatrixGate(self.single_qubit_operations_after[1]).on(b),
     ]
Beispiel #6
0
def test_two_qubit_state_tomography():
    # Check that the density matrices of the four Bell states closely match
    # the ideal cases. In addition, check that the output states of
    # single-qubit rotations (H, H), (X/2, Y/2), (Y/2, X/2) have the correct
    # density matrices.

    simulator = sim.Simulator()
    q_0 = GridQubit(0, 0)
    q_1 = GridQubit(0, 1)

    circuit_00 = circuits.Circuit.from_ops(ops.H(q_0), ops.CNOT(q_0, q_1))
    circuit_01 = circuits.Circuit.from_ops(ops.X(q_1), ops.H(q_0),
                                           ops.CNOT(q_0, q_1))
    circuit_10 = circuits.Circuit.from_ops(ops.X(q_0), ops.H(q_0),
                                           ops.CNOT(q_0, q_1))
    circuit_11 = circuits.Circuit.from_ops(ops.X(q_0), ops.X(q_1), ops.H(q_0),
                                           ops.CNOT(q_0, q_1))
    circuit_hh = circuits.Circuit.from_ops(ops.H(q_0), ops.H(q_1))
    circuit_xy = circuits.Circuit.from_ops(ops.X(q_0)**0.5, ops.Y(q_1)**0.5)
    circuit_yx = circuits.Circuit.from_ops(ops.Y(q_0)**0.5, ops.X(q_1)**0.5)

    act_rho_00 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_00,
                                            1000).data
    act_rho_01 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_01,
                                            1000).data
    act_rho_10 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_10,
                                            1000).data
    act_rho_11 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_11,
                                            1000).data
    act_rho_hh = two_qubit_state_tomography(simulator, q_0, q_1, circuit_hh,
                                            1000).data
    act_rho_xy = two_qubit_state_tomography(simulator, q_0, q_1, circuit_xy,
                                            1000).data
    act_rho_yx = two_qubit_state_tomography(simulator, q_0, q_1, circuit_yx,
                                            1000).data

    tar_rho_00 = np.outer([1.0, 0, 0, 1.0], [1.0, 0, 0, 1.0]) * 0.5
    tar_rho_01 = np.outer([0, 1.0, 1.0, 0], [0, 1.0, 1.0, 0]) * 0.5
    tar_rho_10 = np.outer([1.0, 0, 0, -1.0], [1.0, 0, 0, -1.0]) * 0.5
    tar_rho_11 = np.outer([0, 1.0, -1.0, 0], [0, 1.0, -1.0, 0]) * 0.5
    tar_rho_hh = np.outer([0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5])
    tar_rho_xy = np.outer([0.5, 0.5, -0.5j, -0.5j], [0.5, 0.5, 0.5j, 0.5j])
    tar_rho_yx = np.outer([0.5, -0.5j, 0.5, -0.5j], [0.5, 0.5j, 0.5, 0.5j])

    np.testing.assert_almost_equal(act_rho_00, tar_rho_00, decimal=1)
    np.testing.assert_almost_equal(act_rho_01, tar_rho_01, decimal=1)
    np.testing.assert_almost_equal(act_rho_10, tar_rho_10, decimal=1)
    np.testing.assert_almost_equal(act_rho_11, tar_rho_11, decimal=1)
    np.testing.assert_almost_equal(act_rho_hh, tar_rho_hh, decimal=1)
    np.testing.assert_almost_equal(act_rho_xy, tar_rho_xy, decimal=1)
    np.testing.assert_almost_equal(act_rho_yx, tar_rho_yx, decimal=1)
Beispiel #7
0
def test_controlled_op_to_gates_concrete_case():
    qc = ops.QubitId()
    qt = ops.QubitId()
    operations = decompositions.controlled_op_to_native_gates(
        control=qc,
        target=qt,
        operation=np.array([[1, 1j], [1j, 1]]) * np.sqrt(0.5),
        tolerance=0.0001)

    assert operations == [
        ops.Y(qt)**-0.5,
        ops.CZ(qc, qt)**1.5,
        ops.Z(qc)**0.25,
        ops.Y(qt)**0.5
    ]
Beispiel #8
0
def test_to_from_braket_common_one_qubit_gates():
    """These gates should stay the same (i.e., not get decomposed) when
    converting Cirq -> Braket -> Cirq.
    """
    rots = [ops.rx, ops.ry, ops.rz]
    angles = [1 / 5, 3 / 5, -4 / 5]
    qubit = LineQubit(0)
    cirq_circuit = Circuit(
        # Paulis.
        ops.X(qubit),
        ops.Y(qubit),
        ops.Z(qubit),
        # Single-qubit rotations.
        [rot(angle).on(qubit) for rot, angle in zip(rots, angles)],
        # Rz alter egos.
        ops.T(qubit),
        ops.T(qubit)**-1,
        ops.S(qubit),
        ops.S(qubit)**-1,
        # Rx alter egos.
        ops.X(qubit)**0.5,
        ops.X(qubit)**-0.5,
    )

    test_circuit = from_braket(to_braket(cirq_circuit))
    assert _equal(test_circuit, cirq_circuit, require_qubit_equality=True)
Beispiel #9
0
def test_equality():
    a = ops.QubitId()
    b = ops.QubitId()
    c = ops.QubitId()
    d = ops.QubitId()

    eq = EqualsTester()

    # Default is empty. Iterables get frozen into tuples.
    eq.add_equality_group(Moment(),
                          Moment([]), Moment(()))
    eq.add_equality_group(
        Moment([ops.X(d)]), Moment((ops.X(d),)))

    # Equality depends on gate and qubits.
    eq.add_equality_group(Moment([ops.X(a)]))
    eq.add_equality_group(Moment([ops.X(b)]))
    eq.add_equality_group(Moment([ops.Y(a)]))

    # Equality depends on order.
    eq.add_equality_group(Moment([ops.X(a), ops.X(b)]))
    eq.add_equality_group(Moment([ops.X(b), ops.X(a)]))

    # Two qubit gates.
    eq.make_equality_pair(lambda: Moment([ops.CZ(c, d)]))
    eq.make_equality_pair(lambda: Moment([ops.CZ(a, c)]))
    eq.make_equality_pair(lambda: Moment([ops.CZ(a, b), ops.CZ(c, d)]))
    eq.make_equality_pair(lambda: Moment([ops.CZ(a, c), ops.CZ(b, d)]))
def _cpmg_circuit(qubit: devices.GridQubit, delay_var: sympy.Symbol,
                  max_pulses: int) -> 'cirq.Circuit':
    """Creates a CPMG circuit for a given qubit.

    The circuit will look like:

      sqrt(Y) - wait(delay_var) - X - wait(2*delay_var) - ... - wait(delay_var)

    with max_pulses number of X gates.

    The X gates are paramterizd by 'pulse_N' symbols so that pulses can be
    turned on and off.  This is done to combine circuits with different pulses
    into the same paramterized circuit.
    """
    circuit = circuits.Circuit(
        ops.Y(qubit)**0.5,
        ops.WaitGate(value.Duration(nanos=delay_var))(qubit), ops.X(qubit))
    for n in range(max_pulses):
        pulse_n_on = sympy.Symbol(f'pulse_{n}')
        circuit.append(
            ops.WaitGate(value.Duration(nanos=2 * delay_var *
                                        pulse_n_on))(qubit))
        circuit.append(ops.X(qubit)**pulse_n_on)
    circuit.append(ops.WaitGate(value.Duration(nanos=delay_var))(qubit))
    return circuit
Beispiel #11
0
def test_text_diagrams():
    a = ops.NamedQubit('a')
    b = ops.NamedQubit('b')
    circuit = Circuit.from_ops(ops.SWAP(a, b), ops.X(a), ops.Y(a), ops.Z(a),
                               ops.CZ(a, b), ops.CNOT(a, b), ops.CNOT(b, a),
                               ops.H(a))
    assert circuit.to_text_diagram().strip() == """
a: ───×───X───Y───Z───@───@───X───H───
      │               │   │   │
b: ───×───────────────@───X───@───────
    """.strip()
Beispiel #12
0
def test_clears_known_empties_even_at_zero_tolerance():
    m = circuits.DropNegligible(0.001)
    q = ops.QubitId()
    q2 = ops.QubitId()
    c = circuits.Circuit.from_ops(
        ops.Z(q)**0,
        ops.Y(q)**0.0000001,
        ops.X(q)**-0.0000001,
        ops.CZ(q, q2)**0)

    m.optimize_circuit(c)
    assert c == circuits.Circuit([circuits.Moment()] * 4)
def _two_qubit_clifford_mixers(q_0: 'cirq.Qid', q_1: 'cirq.Qid', idx_2: int,
                               cliffords: Cliffords
                              ) -> Iterator['cirq.OP_TREE']:
    """Fulfills parts (b-d) for two-qubit Cliffords."""
    s1 = cliffords.s1
    s1_x = cliffords.s1_x
    s1_y = cliffords.s1_y
    if idx_2 == 1:
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**-0.5
        yield ops.Y(q_1)**0.5
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**0.5
        yield ops.Y(q_1)**-0.5
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_1)**0.5
    elif 2 <= idx_2 <= 10:
        yield ops.CZ(q_0, q_1)
        idx_3 = int((idx_2 - 2) / 3)
        idx_4 = (idx_2 - 2) % 3
        yield _single_qubit_gates(s1[idx_3], q_0)
        yield _single_qubit_gates(s1_y[idx_4], q_1)
    elif idx_2 >= 11:
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**0.5
        yield ops.X(q_1)**-0.5
        yield ops.CZ(q_0, q_1)
        idx_3 = int((idx_2 - 11) / 3)
        idx_4 = (idx_2 - 11) % 3
        yield _single_qubit_gates(s1_y[idx_3], q_0)
        yield _single_qubit_gates(s1_x[idx_4], q_1)
def _xx_yy_interaction_via_full_czs(q0: 'cirq.Qid', q1: 'cirq.Qid', x: float, y: float):
    a = x * -2 / np.pi
    b = y * -2 / np.pi
    yield ops.X(q0) ** 0.5
    yield ops.H(q1)
    yield ops.CZ(q0, q1)
    yield ops.H(q1)
    yield ops.X(q0) ** a
    yield ops.Y(q1) ** b
    yield ops.H(q1)
    yield ops.CZ(q0, q1)
    yield ops.H(q1)
    yield ops.X(q0) ** -0.5
def test_works_with_basic_gates():
    a = ops.NamedQubit('a')
    b = ops.NamedQubit('b')

    basics = [
        ops.X(a),
        ops.Y(a)**0.5,
        ops.Z(a),
        ops.CZ(a, b)**-0.25,
        ops.CNOT(a, b),
        ops.H(b),
        ops.SWAP(a, b)
    ]
    assert list(ops.inverse_of_invertible_op_tree(basics)) == [
        ops.SWAP(a, b),
        ops.H(b),
        ops.CNOT(a, b),
        ops.CZ(a, b)**0.25,
        ops.Z(a),
        ops.Y(a)**-0.5,
        ops.X(a),
    ]
Beispiel #16
0
def nonoptimal_toffoli_circuit(
    q0: 'cirq.Qid',
    q1: 'cirq.Qid',
    q2: 'cirq.Qid',
    device: devices.Device = devices.UNCONSTRAINED_DEVICE,
) -> circuits.Circuit:
    ret = circuits.Circuit(
        ops.Y(q2) ** 0.5,
        ops.X(q2),
        ops.CNOT(q1, q2),
        ops.Z(q2) ** -0.25,
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q0, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.Z(q2) ** 0.25,
        ops.CNOT(q1, q2),
        ops.Z(q2) ** -0.25,
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q0, q1),
        ops.CNOT(q1, q2),
        ops.CNOT(q2, q1),
        ops.CNOT(q1, q2),
        ops.Z(q2) ** 0.25,
        ops.Z(q1) ** 0.25,
        ops.CNOT(q0, q1),
        ops.Z(q0) ** 0.25,
        ops.Z(q1) ** -0.25,
        ops.CNOT(q0, q1),
        ops.Y(q2) ** 0.5,
        ops.X(q2),
    )
    ret._device = device
    return ret
Beispiel #17
0
def swap_to_sqrt_iswap(a, b, turns):
    """Implement the evolution of the hopping term using two sqrt_iswap gates
     and single-qubit operations. Output unitary:
    [[1, 0,        0,     0],
     [0, g·c,    -i·g·s,  0],
     [0, -i·g·s,  g·c,    0],
     [0,   0,      0,     1]]
     where c = cos(theta) and s = sin(theta).
        Args:
            a: the first qubit
            b: the second qubit
            theta: The rotational angle that specifies the gate, where
            c = cos(π·t/2), s = sin(π·t/2), g = exp(i·π·t/2).
    """
    if not isinstance(turns, sympy.Basic) and _near_mod_n(turns, 1.0, 2):
        # Decomposition for cirq.SWAP
        yield ops.Y(a)**0.5
        yield ops.Y(b)**0.5
        yield SQRT_ISWAP(a, b)
        yield ops.Y(a)**-0.5
        yield ops.Y(b)**-0.5
        yield SQRT_ISWAP(a, b)
        yield ops.X(a)**-0.5
        yield ops.X(b)**-0.5
        yield SQRT_ISWAP(a, b)
        yield ops.X(a)**0.5
        yield ops.X(b)**0.5
        return

    yield ops.Z(a)**1.25
    yield ops.Z(b)**-0.25
    yield ops.ISWAP(a, b)**-0.5
    yield ops.Z(a)**(-turns / 2 + 1)
    yield ops.Z(b)**(turns / 2)
    yield ops.ISWAP(a, b)**-0.5
    yield ops.Z(a)**(turns / 2 - 0.25)
    yield ops.Z(b)**(turns / 2 + 0.25)
    yield ops.CZ.on(a, b)**(-turns)
Beispiel #18
0
def test_combines_sequence():
    m = MergeRotations(0.000001)
    q = ops.QubitId()
    c = circuits.Circuit([
        circuits.Moment([ops.X(q)**0.5]),
        circuits.Moment([ops.Z(q)**0.5]),
        circuits.Moment([ops.X(q)**-0.5]),
    ])

    assert (m.optimization_at(c, 0, c.operation_at(
        q,
        0)) == circuits.PointOptimizationSummary(clear_span=3,
                                                 clear_qubits=[q],
                                                 new_operations=ops.Y(q)**0.5))
def nonoptimal_toffoli_circuit(
        q0: ops.Qid,
        q1: ops.Qid,
        q2: ops.Qid,
        device: devices.Device = devices.UNCONSTRAINED_DEVICE
) -> circuits.Circuit:
    return circuits.Circuit.from_ops(ops.Y(q2)**0.5,
                                     ops.X(q2),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**-0.25,
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q0, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**0.25,
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**-0.25,
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q0, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**0.25,
                                     ops.Z(q1)**0.25,
                                     ops.CNOT(q0, q1),
                                     ops.Z(q0)**0.25,
                                     ops.Z(q1)**-0.25,
                                     ops.CNOT(q0, q1),
                                     ops.Y(q2)**0.5,
                                     ops.X(q2),
                                     device=device)
def test_single_qubit_state_tomography():
    # Check that the density matrices of the output states of X/2, Y/2 and
    # H + Y gates closely match the ideal cases.
    simulator = sim.Simulator()
    qubit = GridQubit(0, 0)

    circuit_1 = circuits.Circuit(ops.X(qubit)**0.5)
    circuit_2 = circuits.Circuit(ops.Y(qubit)**0.5)
    circuit_3 = circuits.Circuit(ops.H(qubit), ops.Y(qubit))

    act_rho_1 = single_qubit_state_tomography(simulator, qubit, circuit_1,
                                              1000).data
    act_rho_2 = single_qubit_state_tomography(simulator, qubit, circuit_2,
                                              1000).data
    act_rho_3 = single_qubit_state_tomography(simulator, qubit, circuit_3,
                                              1000).data

    tar_rho_1 = np.array([[0.5, 0.5j], [-0.5j, 0.5]])
    tar_rho_2 = np.array([[0.5, 0.5], [0.5, 0.5]])
    tar_rho_3 = np.array([[0.5, -0.5], [-0.5, 0.5]])

    np.testing.assert_almost_equal(act_rho_1, tar_rho_1, decimal=1)
    np.testing.assert_almost_equal(act_rho_2, tar_rho_2, decimal=1)
    np.testing.assert_almost_equal(act_rho_3, tar_rho_3, decimal=1)
Beispiel #21
0
def nonoptimal_toffoli_circuit(
        q0: ops.Qid,
        q1: ops.Qid,
        q2: ops.Qid,
        device: devices.Device = devices.UnconstrainedDevice
) -> circuits.Circuit:
    return circuits.Circuit.from_ops(ops.Y(q2)**0.5,
                                     ops.X(q2),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**-0.25,
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q0, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**0.25,
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**-0.25,
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q0, q1),
                                     ops.CNOT(q1, q2),
                                     ops.CNOT(q2, q1),
                                     ops.CNOT(q1, q2),
                                     ops.Z(q2)**0.25,
                                     ops.Z(q1)**0.25,
                                     ops.CNOT(q0, q1),
                                     ops.Z(q0)**0.25,
                                     ops.Z(q1)**-0.25,
                                     ops.CNOT(q0, q1),
                                     ops.Y(q2)**0.5,
                                     ops.X(q2),
                                     device=device)
Beispiel #22
0
def single_qubit_state_tomography(
    sampler: 'cirq.Sampler',
    qubit: 'cirq.Qid',
    circuit: 'cirq.AbstractCircuit',
    repetitions: int = 1000,
) -> TomographyResult:
    """Single-qubit state tomography.

    The density matrix of the output state of a circuit is measured by first
    doing projective measurements in the z-basis, which determine the
    diagonal elements of the matrix. A X/2 or Y/2 rotation is then added before
    the z-basis measurement, which determines the imaginary and real parts of
    the off-diagonal matrix elements, respectively.

    See Vandersypen and Chuang, Rev. Mod. Phys. 76, 1037 for details.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        circuit: The circuit to execute on the qubit before tomography.
        repetitions: The number of measurements for each basis rotation.

    Returns:
        A TomographyResult object that stores and plots the density matrix.
    """
    circuit_z = circuit + circuits.Circuit(ops.measure(qubit, key='z'))
    results = sampler.run(circuit_z, repetitions=repetitions)
    rho_11 = np.mean(results.measurements['z'])
    rho_00 = 1.0 - rho_11

    circuit_x = circuits.Circuit(circuit,
                                 ops.X(qubit)**0.5, ops.measure(qubit,
                                                                key='z'))
    results = sampler.run(circuit_x, repetitions=repetitions)
    rho_01_im = np.mean(results.measurements['z']) - 0.5

    circuit_y = circuits.Circuit(circuit,
                                 ops.Y(qubit)**-0.5, ops.measure(qubit,
                                                                 key='z'))
    results = sampler.run(circuit_y, repetitions=repetitions)
    rho_01_re = 0.5 - np.mean(results.measurements['z'])

    rho_01 = rho_01_re + 1j * rho_01_im
    rho_10 = np.conj(rho_01)

    rho = np.array([[rho_00, rho_01], [rho_10, rho_11]])

    return TomographyResult(rho)
Beispiel #23
0
def _xx_yy_zz_interaction_via_full_czs(q0: 'cirq.Qid', q1: 'cirq.Qid',
                                       x: float, y: float, z: float):
    a = x * -2 / np.pi + 0.5
    b = y * -2 / np.pi + 0.5
    c = z * -2 / np.pi + 0.5
    yield ops.X(q0)**0.5
    yield ops.H(q1)
    yield ops.CZ(q0, q1)
    yield ops.H(q1)
    yield ops.X(q0)**a
    yield ops.Y(q1)**b
    yield ops.H.on(q0)
    yield ops.CZ(q1, q0)
    yield ops.H(q0)
    yield ops.X(q1)**-0.5
    yield ops.Z(q1)**c
    yield ops.H(q1)
    yield ops.CZ(q0, q1)
    yield ops.H(q1)
Beispiel #24
0
    def default_decompose(self, qubits: Sequence[ops.QubitId]) -> ops.OP_TREE:
        q0, q1 = qubits
        a = self.x * -2 / np.pi + 0.5
        b = self.y * -2 / np.pi + 0.5
        c = self.z * -2 / np.pi + 0.5

        yield self.before0(q0)
        yield self.before1(q1)

        yield ops.X(q0)**0.5
        yield ops.CNOT(q0, q1)
        yield ops.X(q0)**a
        yield ops.Y(q1)**b
        yield ops.CNOT(q1, q0)
        yield ops.X(q1)**-0.5
        yield ops.Z(q1)**c
        yield ops.CNOT(q0, q1)

        yield self.after0(q0)
        yield self.after1(q1)
def test_from_braket_non_parameterized_single_qubit_gates():
    braket_circuit = BKCircuit()
    instructions = [
        Instruction(braket_gates.I(), target=0),
        Instruction(braket_gates.X(), target=1),
        Instruction(braket_gates.Y(), target=2),
        Instruction(braket_gates.Z(), target=3),
        Instruction(braket_gates.H(), target=0),
        Instruction(braket_gates.S(), target=1),
        Instruction(braket_gates.Si(), target=2),
        Instruction(braket_gates.T(), target=3),
        Instruction(braket_gates.Ti(), target=0),
        Instruction(braket_gates.V(), target=1),
        Instruction(braket_gates.Vi(), target=2),
    ]
    for instr in instructions:
        braket_circuit.add_instruction(instr)
    cirq_circuit = from_braket(braket_circuit)

    for i, op in enumerate(cirq_circuit.all_operations()):
        assert np.allclose(
            instructions[i].operator.to_matrix(), protocols.unitary(op)
        )

    qreg = LineQubit.range(4)
    expected_cirq_circuit = Circuit(
        ops.I(qreg[0]),
        ops.X(qreg[1]),
        ops.Y(qreg[2]),
        ops.Z(qreg[3]),
        ops.H(qreg[0]),
        ops.S(qreg[1]),
        ops.S(qreg[2]) ** -1,
        ops.T(qreg[3]),
        ops.T(qreg[0]) ** -1,
        ops.X(qreg[1]) ** 0.5,
        ops.X(qreg[2]) ** -0.5,
    )
    assert _equal(cirq_circuit, expected_cirq_circuit)
Beispiel #26
0
    def _decompose_(self, qubits: Sequence[ops.Qid]) -> ops.OP_TREE:
        q0, q1 = qubits
        x, y, z = self.kak.interaction_coefficients
        a = x * -2 / np.pi + 0.5
        b = y * -2 / np.pi + 0.5
        c = z * -2 / np.pi + 0.5

        b0, b1 = self.kak.single_qubit_operations_before
        yield QasmUGate.from_matrix(b0).on(q0)
        yield QasmUGate.from_matrix(b1).on(q1)

        yield ops.X(q0)**0.5
        yield ops.CNOT(q0, q1)
        yield ops.X(q0)**a
        yield ops.Y(q1)**b
        yield ops.CNOT(q1, q0)
        yield ops.X(q1)**-0.5
        yield ops.Z(q1)**c
        yield ops.CNOT(q0, q1)

        a0, a1 = self.kak.single_qubit_operations_after
        yield QasmUGate.from_matrix(a0).on(q0)
        yield QasmUGate.from_matrix(a1).on(q1)
Beispiel #27
0
def t2_decay(
    sampler: work.Sampler,
    *,
    qubit: devices.GridQubit,
    experiment_type: 'ExperimentType' = ExperimentType.RAMSEY,
    num_points: int,
    max_delay: 'cirq.DURATION_LIKE',
    min_delay: 'cirq.DURATION_LIKE' = None,
    repetitions: int = 1000,
    delay_sweep: Optional[study.Sweep] = None,
) -> 'cirq.experiments.T2DecayResult':
    """Runs a t2 transverse relaxation experiment.

    Initializes a qubit into a superposition state, evolves the system using
    rules determined by the experiment type and by the delay parameters,
    then rotates back for measurement.  This will measure the phase decoherence
    decay.  This experiment has three types of T2 metrics, each which measure
    a different slice of the noise spectrum.

    For the Ramsey experiment type (often denoted T2*), the state will be
    prepared with a square root Y gate (`cirq.Y ** 0.5`) and then waits for
    a variable amount of time.  After this time, it will do basic state
    tomography to measure the expectation of the Pauli-X and Pauli-Y operators
    by performing either a `cirq.Y ** -0.5` or `cirq.X ** -0.5`.  The square of
    these two measurements is summed to determine the length of the Bloch
    vector. This experiment measures the phase decoherence of the system under
    free evolution.

    For the Hahn echo experiment (often denoted T2 or spin echo), the state
    will also be prepared with a square root Y gate (`cirq.Y ** 0.5`).
    However, during the mid-point of the delay time being measured, a pi-pulse
    (`cirq.X`) gate will be applied to cancel out inhomogeneous dephasing.
    The same method of measuring the final state as Ramsey experiment is applied
    after the second half of the delay period.

    CPMG, or the Carr-Purcell-Meiboom-Gill sequence, is currently not
    implemented.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        experiment_type: The type of T2 test to run.
        num_points: The number of evenly spaced delays to test.
        max_delay: The largest delay to test.
        min_delay: The smallest delay to test. Defaults to no delay.
        repetitions: The number of repetitions of the circuit
             for each delay and for each tomography result.
        delay_sweep: Optional range of time delays to sweep across.  This should
             be a SingleSweep using the 'delay_ns' with values in integer number
             of nanoseconds.  If specified, this will override the max_delay and
             min_delay parameters.  If not specified, the experiment will sweep
             from min_delay to max_delay with linear steps.
    Returns:
        A T2DecayResult object that stores and can plot the data.
    """
    min_delay_dur = value.Duration(min_delay)
    max_delay_dur = value.Duration(max_delay)

    # Input validation
    if repetitions <= 0:
        raise ValueError('repetitions <= 0')
    if max_delay_dur < min_delay_dur:
        raise ValueError('max_delay < min_delay')
    if min_delay_dur < 0:
        raise ValueError('min_delay < 0')

    # Initialize values used in sweeps
    delay_var = sympy.Symbol('delay_ns')
    inv_x_var = sympy.Symbol('inv_x')
    inv_y_var = sympy.Symbol('inv_y')

    if not delay_sweep:
        delay_sweep = study.Linspace(delay_var,
                                     start=min_delay_dur.total_nanos(),
                                     stop=max_delay_dur.total_nanos(),
                                     length=num_points)
    if delay_sweep.keys != ['delay_ns']:
        raise ValueError('delay_sweep must be a SingleSweep '
                         'with delay_ns parameter')

    if experiment_type == ExperimentType.RAMSEY:
        # Ramsey T2* experiment
        # Use sqrt(Y) to flip to the equator.
        # Evolve the state for a given amount of delay time
        # Then measure the state in both X and Y bases.

        circuit = circuits.Circuit(
            ops.Y(qubit)**0.5,
            ops.WaitGate(value.Duration(nanos=delay_var))(qubit),
            ops.X(qubit)**inv_x_var,
            ops.Y(qubit)**inv_y_var,
            ops.measure(qubit, key='output'),
        )
        tomography_sweep = study.Zip(
            study.Points('inv_x', [0.0, -0.5]),
            study.Points('inv_y', [-0.5, 0.0]),
        )
        sweep = study.Product(delay_sweep, tomography_sweep)
    elif experiment_type == ExperimentType.HAHN_ECHO:
        # Hahn / Spin Echo T2 experiment
        # Use sqrt(Y) to flip to the equator.
        # Evolve the state for half the given amount of delay time
        # Flip the state using an X gate
        # Evolve the state for half the given amount of delay time
        # Then measure the state in both X and Y bases.

        circuit = circuits.Circuit(
            ops.Y(qubit)**0.5,
            ops.WaitGate(value.Duration(nanos=0.5 * delay_var))(qubit),
            ops.X(qubit),
            ops.WaitGate(value.Duration(nanos=0.5 * delay_var))(qubit),
            ops.X(qubit)**inv_x_var,
            ops.Y(qubit)**inv_y_var,
            ops.measure(qubit, key='output'),
        )
        tomography_sweep = study.Zip(
            study.Points('inv_x', [0.0, 0.5]),
            study.Points('inv_y', [-0.5, 0.0]),
        )
        sweep = study.Product(delay_sweep, tomography_sweep)
    else:
        raise ValueError(f'Experiment type {experiment_type} not supported')

    # Tabulate measurements into a histogram
    results = sampler.sample(circuit, params=sweep, repetitions=repetitions)

    y_basis_measurements = results[abs(results.inv_y) > 0]
    x_basis_measurements = results[abs(results.inv_x) > 0]
    x_basis_tabulation = pd.crosstab(
        x_basis_measurements.delay_ns,
        x_basis_measurements.output).reset_index()
    y_basis_tabulation = pd.crosstab(
        y_basis_measurements.delay_ns,
        y_basis_measurements.output).reset_index()

    # If all measurements are 1 or 0, fill in the missing column with all zeros.
    for tab in [x_basis_tabulation, y_basis_tabulation]:
        for col_index, name in [(1, 0), (2, 1)]:
            if name not in tab:
                tab.insert(col_index, name, [0] * tab.shape[0])

    # Return the results in a container object
    return T2DecayResult(x_basis_tabulation, y_basis_tabulation)
Beispiel #28
0
def _two_qubit_clifford(q_0: devices.GridQubit, q_1: devices.GridQubit,
                        idx: int,
                        cliffords: Cliffords) -> Iterator[ops.OP_TREE]:
    """Generates a two-qubit Clifford gate.

    An integer (idx) from 0 to 11519 is used to generate a two-qubit Clifford
    gate which is constructed with single-qubit X and Y rotations and CZ gates.
    The decomposition of the Cliffords follow those described in the appendix
    of Barends et al., Nature 508, 500.

    The integer idx is first decomposed into idx_0 (which ranges from 0 to
    23), idx_1 (ranging from 0 to 23) and idx_2 (ranging from 0 to 19). idx_0
    and idx_1 determine the two single-qubit rotations which happen at the
    beginning of all two-qubit Clifford gates. idx_2 determines the
    subsequent gates in the following:

    a) If idx_2 = 0, do nothing so the Clifford is just two single-qubit
    Cliffords (total of 24*24 = 576 possibilities).

    b) If idx_2 = 1, perform a CZ, followed by -Y/2 on q_0 and Y/2 on q_1,
    followed by another CZ, followed by Y/2 on q_0 and -Y/2 on q_1, followed
    by one more CZ and finally a Y/2 on q_1. The Clifford is then a member of
    the SWAP-like class (total of 24*24 = 576 possibilities).

    c) If 2 <= idx_2 <= 10, perform a CZ followed by a member of the S_1
    group on q_0 and a member of the S_1^(Y/2) group on q_1. The Clifford is
    a member of the CNOT-like class (a total of 3*3*24*24 = 5184 possibilities).

    d) If 11 <= idx_2 <= 19, perform a CZ, followed by Y/2 on q_0 and -X/2 on
    q_1, followed by another CZ, and finally a member of the S_1^(Y/2) group on
    q_0 and a member of the S_1^(X/2) group on q_1. The Clifford is a member
    of the iSWAP-like class (a total of 3*3*24*24 = 5184 possibilities).

    Through the above process, all 11520 members of the two-qubit Clifford
    group may be generated.

    Args:
        q_0: The first qubit under test.
        q_1: The second qubit under test.
        idx: An integer from 0 to 11519.
        cliffords: A NamedTuple that contains single-qubit Cliffords from the
            C1, S1, S_1^(X/2) and S_1^(Y/2) groups.
    """
    c1 = cliffords.c1_in_xy
    s1 = cliffords.s1
    s1_x = cliffords.s1_x
    s1_y = cliffords.s1_y

    idx_0 = int(idx / 480)
    idx_1 = int((idx % 480) / 20)
    idx_2 = idx - idx_0 * 480 - idx_1 * 20
    yield _single_qubit_gates(c1[idx_0], q_0)
    yield _single_qubit_gates(c1[idx_1], q_1)
    if idx_2 == 1:
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**-0.5
        yield ops.Y(q_1)**0.5
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**0.5
        yield ops.Y(q_1)**-0.5
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_1)**0.5
    elif 2 <= idx_2 <= 10:
        yield ops.CZ(q_0, q_1)
        idx_3 = int((idx_2 - 2) / 3)
        idx_4 = (idx_2 - 2) % 3
        yield _single_qubit_gates(s1[idx_3], q_0)
        yield _single_qubit_gates(s1_y[idx_4], q_1)
    elif idx_2 >= 11:
        yield ops.CZ(q_0, q_1)
        yield ops.Y(q_0)**0.5
        yield ops.X(q_1)**-0.5
        yield ops.CZ(q_0, q_1)
        idx_3 = int((idx_2 - 11) / 3)
        idx_4 = (idx_2 - 11) % 3
        yield _single_qubit_gates(s1_y[idx_3], q_0)
        yield _single_qubit_gates(s1_x[idx_4], q_1)
Beispiel #29
0
def t2_decay(
    sampler: 'cirq.Sampler',
    *,
    qubit: 'cirq.Qid',
    experiment_type: 'ExperimentType' = ExperimentType.RAMSEY,
    num_points: int,
    max_delay: 'cirq.DURATION_LIKE',
    min_delay: 'cirq.DURATION_LIKE' = None,
    repetitions: int = 1000,
    delay_sweep: Optional[study.Sweep] = None,
    num_pulses: List[int] = None
) -> Union['cirq.experiments.T2DecayResult',
           List['cirq.experiments.T2DecayResult']]:
    """Runs a t2 transverse relaxation experiment.

    Initializes a qubit into a superposition state, evolves the system using
    rules determined by the experiment type and by the delay parameters,
    then rotates back for measurement.  This will measure the phase decoherence
    decay.  This experiment has three types of T2 metrics, each which measure
    a different slice of the noise spectrum.

    For the Ramsey experiment type (often denoted T2*), the state will be
    prepared with a square root Y gate (`cirq.Y ** 0.5`) and then waits for
    a variable amount of time.  After this time, it will do basic state
    tomography to measure the expectation of the Pauli-X and Pauli-Y operators
    by performing either a `cirq.Y ** -0.5` or `cirq.X ** 0.5`.  The square of
    these two measurements is summed to determine the length of the Bloch
    vector. This experiment measures the phase decoherence of the system under
    free evolution.

    For the Hahn echo experiment (often denoted T2 or spin echo), the state
    will also be prepared with a square root Y gate (`cirq.Y ** 0.5`).
    However, during the mid-point of the delay time being measured, a pi-pulse
    (`cirq.X`) gate will be applied to cancel out inhomogeneous dephasing.
    The same method of measuring the final state as Ramsey experiment is applied
    after the second half of the delay period.  See the animation on the wiki
    page https://en.wikipedia.org/wiki/Spin_echo for a visual illustration
    of this experiment.

    CPMG, or the Carr-Purcell-Meiboom-Gill sequence, involves using a sqrt(Y)
    followed by a sequence of pi pulses (X gates) in a specific timing pattern:

        π/2, t, π, 2t, π, ... 2t, π, t

    The first pulse, a sqrt(Y) gate, will put the qubit's state on the Bloch
    equator.  After a delay, successive X gates will refocus dehomogenous
    phase effects by causing them to precess in opposite directions and
    averaging their effects across the entire pulse train.

    This pulse pattern has two variables that can be adjusted.  The first,
    denoted as 't' in the above sequence, is delay, which can be specified
    with `delay_min` and `delay_max` or by using a `delay_sweep`, similar to
    the other experiments.  The second variable is the number of pi pulses
    (X gates).  This can be specified as a list of integers using the
    `num_pulses` parameter.  If multiple different pulses are specified,
    the data will be presented in a data frame with two
    indices (delay_ns and num_pulses).

    See the following reference for more information about CPMG pulse trains:
    Meiboom, S., and D. Gill, “Modified spin-echo method for measuring nuclear
    relaxation times”, Rev. Sci. Inst., 29, 688–691 (1958).
    https://doi.org/10.1063/1.1716296

    Note that interpreting T2 data is fairly tricky and subtle, as it can
    include other effects that need to be accounted for.  For instance,
    amplitude damping (T1) will present as T2 noise and needs to be
    appropriately compensated for to find a true measure of T2.  Due to this
    subtlety and lack of standard way to interpret the data, the fitting
    of the data to an exponential curve and the extrapolation of an actual
    T2 time value is left as an exercise to the reader.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        experiment_type: The type of T2 test to run.
        num_points: The number of evenly spaced delays to test.
        max_delay: The largest delay to test.
        min_delay: The smallest delay to test. Defaults to no delay.
        repetitions: The number of repetitions of the circuit
             for each delay and for each tomography result.
        delay_sweep: Optional range of time delays to sweep across.  This should
             be a SingleSweep using the 'delay_ns' with values in integer number
             of nanoseconds.  If specified, this will override the max_delay and
             min_delay parameters.  If not specified, the experiment will sweep
             from min_delay to max_delay with linear steps.
        num_pulses: For CPMG, a list of the number of pulses to use.
             If multiple pulses are specified, each will be swept on.
    Returns:
        A T2DecayResult object that stores and can plot the data.
    """
    min_delay_dur = value.Duration(min_delay)
    max_delay_dur = value.Duration(max_delay)

    # Input validation
    if repetitions <= 0:
        raise ValueError('repetitions <= 0')
    if max_delay_dur < min_delay_dur:
        raise ValueError('max_delay < min_delay')
    if min_delay_dur < 0:
        raise ValueError('min_delay < 0')
    if num_pulses and experiment_type != ExperimentType.CPMG:
        raise ValueError('num_pulses is only valid for CPMG experiments.')

    # Initialize values used in sweeps
    delay_var = sympy.Symbol('delay_ns')
    inv_x_var = sympy.Symbol('inv_x')
    inv_y_var = sympy.Symbol('inv_y')
    max_pulses = max(num_pulses) if num_pulses else 0

    if not delay_sweep:
        delay_sweep = study.Linspace(delay_var,
                                     start=min_delay_dur.total_nanos(),
                                     stop=max_delay_dur.total_nanos(),
                                     length=num_points)
    if delay_sweep.keys != ['delay_ns']:
        raise ValueError('delay_sweep must be a SingleSweep '
                         'with delay_ns parameter')

    if experiment_type == ExperimentType.RAMSEY:
        # Ramsey T2* experiment
        # Use sqrt(Y) to flip to the equator.
        # Evolve the state for a given amount of delay time
        # Then measure the state in both X and Y bases.

        circuit = circuits.Circuit(
            ops.Y(qubit)**0.5,
            ops.wait(qubit, nanos=delay_var),
        )
    else:
        if experiment_type == ExperimentType.HAHN_ECHO:
            # Hahn / Spin Echo T2 experiment
            # Use sqrt(Y) to flip to the equator.
            # Evolve the state for the given amount of delay time
            # Flip the state using an X gate
            # Evolve the state for the given amount of delay time
            # Then measure the state in both X and Y bases.
            num_pulses = [0]
            # This is equivalent to a CPMG experiment with zero pulses
            # and will follow the same code path.

        # Carr-Purcell-Meiboom-Gill sequence.
        # Performs the following sequence
        # π/2 - wait(t) - π - wait(2t) - ... - π - wait(t)
        # There will be N π pulses (X gates)
        # where N sweeps over the values of num_pulses
        #
        if not num_pulses:
            raise ValueError('At least one value must be given '
                             'for num_pulses in a CPMG experiment')
        circuit = _cpmg_circuit(qubit, delay_var, max_pulses)

    # Add simple state tomography
    circuit.append(ops.X(qubit)**inv_x_var)
    circuit.append(ops.Y(qubit)**inv_y_var)
    circuit.append(ops.measure(qubit, key='output'))
    tomography_sweep = study.Zip(
        study.Points('inv_x', [0.0, 0.5]),
        study.Points('inv_y', [-0.5, 0.0]),
    )

    if num_pulses and max_pulses > 0:
        pulse_sweep = _cpmg_sweep(num_pulses)
        sweep = study.Product(delay_sweep, pulse_sweep, tomography_sweep)
    else:
        sweep = study.Product(delay_sweep, tomography_sweep)

    # Tabulate measurements into a histogram
    results = sampler.sample(circuit, params=sweep, repetitions=repetitions)

    y_basis_measurements = results[abs(results.inv_y) > 0].copy()
    x_basis_measurements = results[abs(results.inv_x) > 0].copy()

    if num_pulses and len(num_pulses) > 1:
        cols = tuple(f'pulse_{t}' for t in range(max_pulses))
        x_basis_measurements[
            'num_pulses'] = x_basis_measurements.loc[:, cols].sum(axis=1)
        y_basis_measurements[
            'num_pulses'] = y_basis_measurements.loc[:, cols].sum(axis=1)

    x_basis_tabulation = _create_tabulation(x_basis_measurements)
    y_basis_tabulation = _create_tabulation(y_basis_measurements)

    # Return the results in a container object
    return T2DecayResult(x_basis_tabulation, y_basis_tabulation)
Beispiel #30
0
    def known_two_q_operations_to_sycamore_operations(
            self, qubit_a: ops.Qid, qubit_b: ops.Qid,
            op: ops.GateOperation) -> ops.OP_TREE:
        """
        Synthesize a known gate operation to a sycamore operation

        This function dispatches based on gate type

        Args:
            qubit_a: first qubit of GateOperation
            qubit_b: second qubit of GateOperation
            op: operation to decompose
        Returns:
            New operations iterable object
        """
        gate = op.gate
        if isinstance(gate, ops.CNotPowGate):
            return [
                ops.Y(qubit_b)**-0.5,
                cphase(
                    cast(ops.CNotPowGate, gate).exponent * np.pi, qubit_a,
                    qubit_b),
                ops.Y(qubit_b)**0.5,
            ]
        elif isinstance(gate, ops.CZPowGate):
            gate = cast(ops.CZPowGate, gate)
            if math.isclose(gate.exponent, 1.0):  # check if CZ or CPHASE
                return decompose_cz_into_syc(qubit_a, qubit_b)
            else:
                # because CZPowGate == diag([1, 1, 1, e^{i pi phi}])
                return cphase(gate.exponent * np.pi, qubit_a, qubit_b)
        elif isinstance(gate, ops.SwapPowGate) and math.isclose(
                cast(ops.SwapPowGate, gate).exponent, 1.0):
            return decompose_swap_into_syc(qubit_a, qubit_b)
        elif isinstance(gate, ops.ISwapPowGate) and math.isclose(
                cast(ops.ISwapPowGate, gate).exponent, 1.0):
            return decompose_iswap_into_syc(qubit_a, qubit_b)
        elif isinstance(gate, ops.ZZPowGate):
            return rzz(
                cast(ops.ZZPowGate, gate).exponent * np.pi / 2, *op.qubits)
        elif isinstance(gate, ops.MatrixGate) and len(op.qubits) == 2:
            new_ops = optimizers.two_qubit_matrix_to_operations(
                op.qubits[0], op.qubits[1], op, allow_partial_czs=True)
            gate_ops = []
            for new_op in new_ops:
                num_qubits = len(new_op.qubits)
                if num_qubits == 1:
                    gate_ops.extend([
                        term.on(new_op.qubits[0])
                        for term in optimizers.single_qubit_matrix_to_gates(
                            protocols.unitary(new_op))
                    ])
                elif num_qubits == 2:
                    gate_ops.extend(
                        ops.flatten_to_ops(
                            self.known_two_q_operations_to_sycamore_operations(
                                new_op.qubits[0], new_op.qubits[1],
                                cast(ops.GateOperation, new_op))))
            return gate_ops
        else:
            raise ValueError("Unrecognized gate: {!r}".format(op))