Ejemplo n.º 1
0
def test_merge_single_qubit_gates_into_phxz_deep():
    a = cirq.NamedQubit("a")
    c_nested = cirq.FrozenCircuit(cirq.H(a), cirq.Z(a),
                                  cirq.H(a).with_tags("ignore"))
    c_nested_merged = cirq.FrozenCircuit(
        _phxz(-0.5, 0.5, 0).on(a),
        cirq.H(a).with_tags("ignore"))
    c_orig = cirq.Circuit(
        c_nested,
        cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"),
        c_nested,
        cirq.CircuitOperation(c_nested).repeat(5).with_tags("preserve_tags"),
        c_nested,
        cirq.CircuitOperation(c_nested).repeat(6),
    )
    c_expected = cirq.Circuit(
        c_nested_merged,
        cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"),
        c_nested_merged,
        cirq.CircuitOperation(c_nested_merged).repeat(5).with_tags(
            "preserve_tags"),
        c_nested_merged,
        cirq.CircuitOperation(c_nested_merged).repeat(6),
    )
    context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True)
    c_new = cirq.merge_single_qubit_gates_to_phxz(c_orig, context=context)
    cirq.testing.assert_same_circuits(c_new, c_expected)
Ejemplo n.º 2
0
def test_merge_single_qubit_gates_into_phxz():
    def phxz(a, x, z):
        return cirq.PhasedXZGate(
            axis_phase_exponent=a,
            x_exponent=x,
            z_exponent=z,
        )

    a, b = cirq.LineQubit.range(2)
    c = cirq.Circuit(
        cirq.X(a),
        cirq.Y(b) ** 0.5,
        cirq.CZ(a, b),
        cirq.H(a),
        cirq.Z(a),
        cirq.measure(b, key="m"),
        cirq.H(a).with_classical_controls("m"),
    )
    assert_optimizes(
        optimized=cirq.merge_single_qubit_gates_to_phxz(c),
        expected=cirq.Circuit(
            phxz(-1, 1, 0).on(a),
            phxz(0.5, 0.5, 0).on(b),
            cirq.CZ(a, b),
            phxz(-0.5, 0.5, 0).on(a),
            cirq.measure(b, key="m"),
            cirq.H(a).with_classical_controls("m"),
        ),
    )
Ejemplo n.º 3
0
def optimized_for_sycamore(
    circuit: cirq.Circuit,
    *,
    qubit_map: Callable[[cirq.Qid], cirq.GridQubit] = lambda e: cast(cirq.GridQubit, e),
    optimizer_type: str = 'sqrt_iswap',
    tolerance: float = 1e-5,
    tabulation_resolution: Optional[float] = None,
) -> cirq.Circuit:
    """Optimizes a circuit for Google devices.

    Uses a set of optimizers that will compile to the proper gateset for the
    device (xmon, sqrt_iswap, or sycamore gates) and then use optimizers to
    compress the gate depth down as much as is easily algorithmically possible
    by merging rotations, ejecting Z gates, etc.

    Args:
        circuit: The circuit to optimize.
        qubit_map: Transforms the qubits (e.g. so that they are GridQubits).
        optimizer_type: A string defining the optimizations to apply.
            Possible values are  'xmon', 'xmon_partial_cz', 'sqrt_iswap',
            'sycamore'
        tolerance: The tolerance passed to the various circuit optimization
            passes.
        tabulation_resolution: If provided, compute a gateset tabulation
            with the specified resolution and use it to approximately
            compile arbitrary two-qubit gates for which an analytic compilation
            is not known.
    Returns:
        The optimized circuit.

    Raises:
        ValueError: If the `optimizer_type` is not a supported type.
    """
    copy = circuit.copy()
    if optimizer_type not in _TARGET_GATESETS:
        raise ValueError(
            f'{optimizer_type} is not an allowed type.  Allowed '
            f'types are: {_TARGET_GATESETS.keys()}'
        )

    tabulation: Optional[cirq.TwoQubitGateTabulation] = None
    if tabulation_resolution is not None:
        tabulation = _gate_product_tabulation_cached(optimizer_type, tabulation_resolution)

    if optimizer_type in _TARGET_GATESETS:
        copy = cirq.optimize_for_target_gateset(
            circuit,
            gateset=_TARGET_GATESETS[optimizer_type](tolerance, tabulation),
            context=cirq.TransformerContext(deep=True),
        )
    copy = cirq.merge_single_qubit_gates_to_phxz(copy, atol=tolerance)
    copy = cirq.eject_phased_paulis(copy, atol=tolerance)
    copy = cirq.eject_z(copy, atol=tolerance)
    copy = cirq.drop_negligible_operations(copy, atol=tolerance)

    ret = cirq.Circuit(
        (op.transform_qubits(qubit_map) for op in copy.all_operations()),
        strategy=cirq.InsertStrategy.EARLIEST,
    )
    return ret
Ejemplo n.º 4
0
def two_qubit_matrix_to_sycamore_operations(
    q0: cirq.Qid,
    q1: cirq.Qid,
    mat: np.ndarray,
    *,
    atol: float = 1e-8,
    clean_operations: bool = True,
) -> cirq.OP_TREE:
    """Decomposes a two-qubit unitary matrix into `cirq_google.SYC` + single qubit rotations.

    The analytical decomposition first Synthesizes the given operation using `cirq.CZPowGate` +
    single qubit rotations and then decomposes each `cirq.CZPowGate` into `cirq_google.SYC` +
    single qubit rotations using `cirq_google.known_2q_op_to_sycamore_operations`.

    Note that the resulting decomposition may not be optimal, and users should first try to
    decompose a given operation using `cirq_google.known_2q_op_to_sycamore_operations`.

    Args:
        q0: The first qubit being operated on.
        q1: The other qubit being operated on.
        mat: Defines the operation to apply to the pair of qubits.
        atol: A limit on the amount of absolute error introduced by the
            construction.
        clean_operations: Merges runs of single qubit gates to a single `cirq.PhasedXZGate` in
            the resulting operations list.

    Returns:
        A `cirq.OP_TREE` that implements the given unitary operation using only `cirq_google.SYC` +
        single qubit rotations.
    """
    decomposed_ops: List[cirq.OP_TREE] = []
    for op in cirq.two_qubit_matrix_to_cz_operations(
            q0,
            q1,
            mat,
            allow_partial_czs=True,
            atol=atol,
            clean_operations=clean_operations):
        if cirq.num_qubits(op) == 2:
            decomposed_cphase = known_2q_op_to_sycamore_operations(op)
            assert decomposed_cphase is not None
            decomposed_ops.append(decomposed_cphase)
        else:
            decomposed_ops.append(op)
    return ([
        *cirq.merge_single_qubit_gates_to_phxz(
            cirq.Circuit(decomposed_ops)).all_operations()
    ] if clean_operations else decomposed_ops)
Ejemplo n.º 5
0
    def _convert_one(self, op: cirq.Operation) -> cirq.OP_TREE:
        """The main conversion step for the PointOptimizer."""
        if not (cirq.has_unitary(op) and 1 <= cirq.num_qubits(op) <= 2):
            return NotImplemented

        if cirq.num_qubits(op) == 1:
            return [
                *cirq.merge_single_qubit_gates_to_phxz(
                    cirq.Circuit(op)).all_operations()
            ]

        known_decomp = two_qubit_to_sycamore.known_2q_op_to_sycamore_operations(
            op)
        if known_decomp is not None:
            return known_decomp
        if self.tabulation is not None:
            return two_qubit_to_sycamore._decompose_arbitrary_into_syc_tabulation(
                op, self.tabulation)
        return two_qubit_to_sycamore.two_qubit_matrix_to_sycamore_operations(
            op.qubits[0], op.qubits[1], cirq.unitary(op))
Ejemplo n.º 6
0
def test_merge_single_qubit_gates_into_phxz():
    a, b = cirq.LineQubit.range(2)
    c = cirq.Circuit(
        cirq.X(a),
        cirq.Y(b)**0.5,
        cirq.CZ(a, b),
        cirq.H(a),
        cirq.Z(a),
        cirq.measure(b, key="m"),
        cirq.H(a).with_classical_controls("m"),
    )
    assert_optimizes(
        optimized=cirq.merge_single_qubit_gates_to_phxz(c),
        expected=cirq.Circuit(
            _phxz(-1, 1, 0).on(a),
            _phxz(0.5, 0.5, 0).on(b),
            cirq.CZ(a, b),
            _phxz(-0.5, 0.5, 0).on(a),
            cirq.measure(b, key="m"),
            cirq.H(a).with_classical_controls("m"),
        ),
    )