def decompose_to_target_gateset(self, op: 'cirq.Operation',
                                 moment_idx: int) -> DecomposeResult:
     if not 1 <= protocols.num_qubits(op) <= 2:
         return self._decompose_multi_qubit_operation(op, moment_idx)
     if protocols.num_qubits(op) == 1:
         return self._decompose_single_qubit_operation(op, moment_idx)
     new_optree = self._decompose_two_qubit_operation(op, moment_idx)
     if new_optree is NotImplemented or new_optree is None:
         return new_optree
     new_optree = [*ops.flatten_to_ops_or_moments(new_optree)]
     op_untagged = op.untagged
     old_optree = ([*op_untagged.circuit]
                   if isinstance(op_untagged, circuits.CircuitOperation)
                   and self._intermediate_result_tag in op.tags else [op])
     old_2q_gate_count = sum(1 for o in ops.flatten_to_ops(old_optree)
                             if len(o.qubits) == 2)
     new_2q_gate_count = sum(1 for o in ops.flatten_to_ops(new_optree)
                             if len(o.qubits) == 2)
     switch_to_new = (any(
         protocols.num_qubits(op) == 2 and op not in self
         for op in ops.flatten_to_ops(old_optree))
                      or new_2q_gate_count < old_2q_gate_count)
     if switch_to_new:
         return new_optree
     mapped_old_optree: List['cirq.OP_TREE'] = []
     for old_op in ops.flatten_to_ops(old_optree):
         if old_op in self:
             mapped_old_optree.append(old_op)
         else:
             decomposed_op = self._decompose_single_qubit_operation(
                 old_op, moment_idx)
             if decomposed_op is None or decomposed_op is NotImplemented:
                 return NotImplemented
             mapped_old_optree.append(decomposed_op)
     return mapped_old_optree
Exemplo n.º 2
0
    def __init__(
        self,
        operations: 'cirq.OP_TREE',
        qubits: Tuple['cirq.Qid', ...],
        header: str = '',
        precision: int = 10,
        version: str = '2.0',
    ) -> None:
        """Representation of a circuit in QASM format.

        Args:
            operations: Tree of operations to insert.
            qubits: The qubits used in the operations.
            header: A multi-line string that is placed in a comment at the top
                of the QASM.
            precision: The number of digits after the decimal to show for
                numbers in the QASM code.
            version: The QASM version to target. Objects may return different
                QASM depending on version.
        """
        self.operations = tuple(ops.flatten_to_ops(operations))
        self.qubits = qubits
        self.header = header
        self.measurements = tuple(op for op in self.operations
                                  if isinstance(op.gate, ops.MeasurementGate))
        meas_key_id_map, meas_comments = self._generate_measurement_ids()
        self.meas_comments = meas_comments
        qubit_id_map = self._generate_qubit_ids()
        self.args = protocols.QasmArgs(
            precision=precision,
            version=version,
            qubit_id_map=qubit_id_map,
            meas_key_id_map=meas_key_id_map,
        )
Exemplo n.º 3
0
def decompose_arbitrary_into_syc_analytic(qubit_a: ops.Qid, qubit_b: ops.Qid,
                                          op: ops.GateOperation):
    """Synthesize an arbitrary 2 qubit operation to a sycamore operation using
    the given Tabulation.

     Args:
            qubit_a: first qubit of the operation
            qubit_b: second qubit of the operation
            op: operation to decompose
            tabulation: A tabulation for the Sycamore gate.
        Returns:
            New operations iterable object
     """
    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(
                    known_two_q_operations_to_sycamore_operations(
                        new_op.qubits[0], new_op.qubits[1],
                        cast(ops.GateOperation, new_op))))
    return gate_ops
Exemplo n.º 4
0
    def _core_iterator(
        self,
        circuit: circuits.Circuit,
        sim_state: 'MPSState',
    ):
        """Iterator over MPSSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit to simulate.
            sim_state: The initial state args for the simulation in the
                computational basis.

        Yields:
            MPSStepResult from simulating a Moment of the Circuit.
        """
        if len(circuit) == 0:
            yield MPSSimulatorStepResult(
                measurements=sim_state.log_of_measurement_results, state=sim_state
            )
            return

        noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            for op in flatten_to_ops(op_tree):
                if protocols.is_measurement(op) or protocols.has_mixture(op):
                    sim_state.axes = tuple(sim_state.qubit_map[qubit] for qubit in op.qubits)
                    protocols.act_on(op, sim_state)
                else:
                    raise NotImplementedError(f"Unrecognized operation: {op!r}")

            yield MPSSimulatorStepResult(
                measurements=sim_state.log_of_measurement_results, state=sim_state
            )
            sim_state.log_of_measurement_results.clear()
def decompose_arbitrary_into_syc_analytic(qubit_a: ops.Qid, qubit_b: ops.Qid,
                                          op: ops.Operation) -> ops.OP_TREE:
    """Synthesize an arbitrary 2 qubit operation to a sycamore operation using
    the given Tabulation.

     Args:
            qubit_a: first qubit of the operation
            qubit_b: second qubit of the operation
            op: operation to decompose
            tabulation: A tabulation for the Sycamore gate.
        Returns:
            New operations iterable object
    """
    new_ops = optimizers.two_qubit_matrix_to_operations(qubit_a,
                                                        qubit_b,
                                                        op,
                                                        allow_partial_czs=True)
    for new_op in new_ops:
        num_qubits = len(new_op.qubits)
        if num_qubits == 1:
            (a, ) = new_op.qubits
            yield from _phased_x_z_ops(protocols.unitary(new_op), a)
        elif num_qubits == 2:
            a, b = op.qubits
            yield from ops.flatten_to_ops(
                known_two_q_operations_to_sycamore_operations(a, b, new_op))
Exemplo n.º 6
0
    def _base_iterator(
        self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
        initial_state: int
    ) -> Iterator['cirq.contrib.quimb.mps_simulator.MPSSimulatorStepResult']:
        """Iterator over MPSSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit to simulate.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.
            initial_state: The initial state for the simulation in the
                computational basis. Represented as a big endian int.

        Yields:
            MPSStepResult from simulating a Moment of the Circuit.
        """
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())

        qubit_map = {q: i for i, q in enumerate(qubits)}

        if len(circuit) == 0:
            yield MPSSimulatorStepResult(
                measurements={},
                state=MPSState(
                    qubit_map,
                    self.simulation_options,
                    self.grouping,
                    initial_state=initial_state,
                ),
            )
            return

        state = MPSState(
            qubit_map,
            self.simulation_options,
            self.grouping,
            initial_state=initial_state,
        )

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            measurements: Dict[str, List[int]] = collections.defaultdict(list)

            for op in flatten_to_ops(op_tree):
                if isinstance(op.gate, ops.MeasurementGate):
                    key = str(protocols.measurement_key(op))
                    measurements[key].extend(
                        state.perform_measurement(op.qubits, self.prng))
                elif protocols.has_mixture(op):
                    state.apply_op(op, self.prng)
                else:
                    raise NotImplementedError(
                        f"Unrecognized operation: {op!r}")

            yield MPSSimulatorStepResult(measurements=measurements,
                                         state=state)
Exemplo n.º 7
0
    def _core_iterator(
        self,
        circuit: circuits.AbstractCircuit,
        sim_state: OperationTarget[TActOnArgs],
        all_measurements_are_terminal: bool = False,
    ) -> Iterator[TStepResultBase]:
        """Standard iterator over StepResult from Moments of a Circuit.

        Args:
            circuit: The circuit to simulate.
            sim_state: The initial args for the simulation. The form of
                this state depends on the simulation implementation. See
                documentation of the implementing class for details.
            all_measurements_are_terminal: Whether all measurements in the
                given circuit are terminal.

        Yields:
            StepResults from simulating a Moment of the Circuit.

        Raises:
            TypeError: The simulator encounters an op it does not support.
        """

        if len(circuit) == 0:
            yield self._create_step_result(sim_state)
            return

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        measured: Dict[Tuple['cirq.Qid', ...],
                       bool] = collections.defaultdict(bool)
        for moment in noisy_moments:
            for op in ops.flatten_to_ops(moment):
                try:
                    # TODO: support more general measurements.
                    # Github issue: https://github.com/quantumlib/Cirq/issues/3566

                    # Preprocess measurements
                    if all_measurements_are_terminal and measured[op.qubits]:
                        continue
                    if isinstance(op.gate, ops.MeasurementGate):
                        measured[op.qubits] = True
                        if all_measurements_are_terminal:
                            continue
                        if self._ignore_measurement_results:
                            op = ops.phase_damp(1).on(*op.qubits)

                    # Simulate the operation
                    protocols.act_on(op, sim_state)
                except TypeError:
                    raise TypeError(
                        f"{self.__class__.__name__} doesn't support {op!r}")

            step_result = self._create_step_result(sim_state)
            yield step_result
            sim_state = step_result._sim_state
Exemplo n.º 8
0
    def _base_iterator(
            self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
            initial_state: int) -> Iterator['MPSSimulatorStepResult']:
        """Iterator over MPSSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit to simulate.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.
            initial_state: The initial state for the simulation in the
                computational basis. Represented as a big endian int.

        Yields:
            MPSStepResult from simulating a Moment of the Circuit.
        """
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())

        qubit_map = {q: i for i, q in enumerate(qubits)}

        if len(circuit) == 0:
            yield MPSSimulatorStepResult(
                measurements={},
                state=MPSState(
                    qubit_map,
                    self.prng,
                    self.simulation_options,
                    self.grouping,
                    initial_state=initial_state,
                ),
            )
            return

        state = MPSState(
            qubit_map,
            self.prng,
            self.simulation_options,
            self.grouping,
            initial_state=initial_state,
        )

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            for op in flatten_to_ops(op_tree):
                if protocols.is_measurement(op) or protocols.has_mixture(op):
                    state.axes = tuple(qubit_map[qubit] for qubit in op.qubits)
                    protocols.act_on(op, state)
                else:
                    raise NotImplementedError(
                        f"Unrecognized operation: {op!r}")

            yield MPSSimulatorStepResult(
                measurements=state.log_of_measurement_results, state=state)
            state.log_of_measurement_results.clear()
Exemplo n.º 9
0
    def _core_iterator(
        self,
        circuit: circuits.Circuit,
        sim_state: act_on_density_matrix_args.ActOnDensityMatrixArgs,
        all_measurements_are_terminal: bool = False,
    ):
        """Iterator over DensityMatrixStepResult from Moments of a Circuit

        Args:
            circuit: The circuit to simulate.
            sim_state: The initial state args for the simulation in the
                computational basis.
            all_measurements_are_terminal: Indicator that all measurements
                are terminal, allowing optimization.

        Yields:
            DensityMatrixStepResult from simulating a Moment of the Circuit.
        """
        if len(circuit) == 0:
            yield DensityMatrixStepResult(
                density_matrix=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=sim_state.qubit_map,
                dtype=self._dtype,
            )
            return

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        measured = collections.defaultdict(
            bool)  # type: Dict[Tuple[cirq.Qid, ...], bool]
        for moment in noisy_moments:
            for op in flatten_to_ops(moment):
                # TODO: support more general measurements.
                # Github issue: https://github.com/quantumlib/Cirq/issues/3566
                if all_measurements_are_terminal and measured[op.qubits]:
                    continue
                if protocols.is_measurement(op):
                    measured[op.qubits] = True
                    if all_measurements_are_terminal:
                        continue
                    if self._ignore_measurement_results:
                        op = ops.phase_damp(1).on(*op.qubits)
                sim_state.axes = tuple(sim_state.qubit_map[qubit]
                                       for qubit in op.qubits)
                protocols.act_on(op, sim_state)

            yield DensityMatrixStepResult(
                density_matrix=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=sim_state.qubit_map,
                dtype=self._dtype,
            )
            sim_state.log_of_measurement_results.clear()
Exemplo n.º 10
0
def assert_decompose_ends_at_default_gateset(val: Any):
    """Asserts that cirq.decompose(val) ends at default cirq gateset or a known gate."""
    if _known_gate_with_no_decomposition(val):
        return  # coverage: ignore
    args = () if isinstance(val, ops.Operation) else (tuple(
        devices.LineQid.for_gate(val)), )
    dec_once = protocols.decompose_once(val, [val(*args[0]) if args else val],
                                        *args)
    for op in [*ops.flatten_to_ops(protocols.decompose(d) for d in dec_once)]:
        assert _known_gate_with_no_decomposition(op.gate) or (
            op in protocols.decompose_protocol.DECOMPOSE_TARGET_GATESET
        ), f'{val} decomposed to {op}, which is not part of default cirq target gateset.'
Exemplo n.º 11
0
    def _core_iterator(
        self,
        circuit: circuits.Circuit,
        sim_state: TActOnArgs,
        all_measurements_are_terminal: bool = False,
    ) -> Iterator[TStepResult]:
        """Standard iterator over StepResult from Moments of a Circuit.

        Args:
            circuit: The circuit to simulate.
            sim_state: The initial args for the simulation. The form of
                this state depends on the simulation implementation. See
                documentation of the implementing class for details.

        Yields:
            StepResults from simulating a Moment of the Circuit.
        """
        if len(circuit) == 0:
            yield self._create_step_result(sim_state, sim_state.qubit_map)
            return

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        measured: Dict[Tuple[cirq.Qid, ...],
                       bool] = collections.defaultdict(bool)
        for moment in noisy_moments:
            for op in ops.flatten_to_ops(moment):
                try:
                    # TODO: support more general measurements.
                    # Github issue: https://github.com/quantumlib/Cirq/issues/3566
                    if all_measurements_are_terminal and measured[op.qubits]:
                        continue
                    if isinstance(op.gate, ops.MeasurementGate):
                        measured[op.qubits] = True
                        if all_measurements_are_terminal:
                            continue
                        if self._ignore_measurement_results:
                            op = ops.phase_damp(1).on(*op.qubits)
                    sim_state.axes = tuple(sim_state.qubit_map[qubit]
                                           for qubit in op.qubits)
                    protocols.act_on(op, sim_state)
                except TypeError:
                    raise TypeError(
                        f"{self.__class__.__name__} doesn't support {op!r}")

            yield self._create_step_result(sim_state, sim_state.qubit_map)
            sim_state.log_of_measurement_results.clear()
Exemplo n.º 12
0
 def __init__(self,
              operations: 'cirq.OP_TREE',
              qubits: Tuple['cirq.Qid', ...],
              header: str = '',
              precision: int = 10,
              version: str = '2.0') -> None:
     self.operations = tuple(ops.flatten_to_ops(operations))
     self.qubits = qubits
     self.header = header
     self.measurements = tuple(op for op in self.operations
                               if isinstance(op.gate, ops.MeasurementGate))
     meas_key_id_map, meas_comments = self._generate_measurement_ids()
     self.meas_comments = meas_comments
     qubit_id_map = self._generate_qubit_ids()
     self.args = protocols.QasmArgs(precision=precision,
                                    version=version,
                                    qubit_id_map=qubit_id_map,
                                    meas_key_id_map=meas_key_id_map)
Exemplo n.º 13
0
    def _base_iterator(
        self,
        circuit: circuits.Circuit,
        qubit_order: ops.QubitOrderOrList,
        initial_state: 'cirq.STATE_VECTOR_LIKE',
        perform_measurements: bool = True,
    ) -> Iterator['SparseSimulatorStep']:
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        num_qubits = len(qubits)
        qid_shape = protocols.qid_shape(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        state = qis.to_valid_state_vector(initial_state,
                                          num_qubits,
                                          qid_shape=qid_shape,
                                          dtype=self._dtype)
        if len(circuit) == 0:
            yield SparseSimulatorStep(state, {}, qubit_map, self._dtype)

        sim_state = act_on_state_vector_args.ActOnStateVectorArgs(
            target_tensor=np.reshape(state, qid_shape),
            available_buffer=np.empty(qid_shape, dtype=self._dtype),
            axes=[],
            prng=self._prng,
            log_of_measurement_results={},
        )

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            for op in flatten_to_ops(op_tree):
                if perform_measurements or not isinstance(
                        op.gate, ops.MeasurementGate):
                    sim_state.axes = tuple(qubit_map[qubit]
                                           for qubit in op.qubits)
                    protocols.act_on(op, sim_state)

            yield SparseSimulatorStep(
                state_vector=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=qubit_map,
                dtype=self._dtype,
            )
            sim_state.log_of_measurement_results.clear()
Exemplo n.º 14
0
    def optimize_circuit(self, circuit: Circuit):
        frontier: Dict['Qid', int] = defaultdict(lambda: 0)
        i = 0
        while i < len(circuit):  # Note: circuit may mutate as we go.
            for op in circuit[i].operations:
                # Don't touch stuff inserted by previous optimizations.
                if any(frontier[q] > i for q in op.qubits):
                    continue

                # Skip if an optimization removed the circuit underneath us.
                if i >= len(circuit):
                    continue
                # Skip if an optimization removed the op we're considering.
                if op not in circuit[i].operations:
                    continue
                opt = self.optimization_at(circuit, i, op)
                # Skip if the optimization did nothing.
                if opt is None:
                    continue

                # Clear target area, and insert new operations.
                circuit.clear_operations_touching(
                    opt.clear_qubits,
                    [e for e in range(i, i + opt.clear_span)])
                new_operations = self.post_clean_up(
                    cast(Tuple[ops.Operation], opt.new_operations))

                flat_new_operations = tuple(ops.flatten_to_ops(new_operations))

                new_qubits = set()
                for flat_op in flat_new_operations:
                    for q in flat_op.qubits:
                        new_qubits.add(q)

                if not new_qubits.issubset(set(opt.clear_qubits)):
                    raise ValueError(
                        'New operations in PointOptimizer should not act on new qubits.'
                    )

                circuit.insert_at_frontier(flat_new_operations, i, frontier)
            i += 1
Exemplo n.º 15
0
    def _core_iterator(
        self,
        circuit: circuits.Circuit,
        sim_state: act_on_state_vector_args.ActOnStateVectorArgs,
    ):
        """Iterator over SparseSimulatorStep from Moments of a Circuit

        Args:
            circuit: The circuit to simulate.
            sim_state: The initial state args for the simulation in the
                computational basis.

        Yields:
            SparseSimulatorStep from simulating a Moment of the Circuit.
        """
        if len(circuit) == 0:
            yield SparseSimulatorStep(
                state_vector=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=sim_state.qubit_map,
                dtype=self._dtype,
            )
            return

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            for op in flatten_to_ops(op_tree):
                sim_state.axes = tuple(sim_state.qubit_map[qubit]
                                       for qubit in op.qubits)
                protocols.act_on(op, sim_state)

            yield SparseSimulatorStep(
                state_vector=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=sim_state.qubit_map,
                dtype=self._dtype,
            )
            sim_state.log_of_measurement_results.clear()
Exemplo n.º 16
0
    def optimize_circuit(self, circuit: Circuit):
        moment_new_ops = defaultdict(
            list)  # type: Dict[int, List['cirq.Operation']]
        circuit_len = len(circuit)
        for i in range(circuit_len):
            moment_new_ops[i] = []
            for op in circuit[i].operations:
                opt = self.optimization_at(circuit, i, op)
                if opt is None:
                    # keep the old operation if the optimization did nothing.
                    moment_new_ops[i].append(op)
                    circuit.clear_operations_touching(op.qubits, [i])
                else:
                    # Clear target area, and insert new operations.
                    circuit.clear_operations_touching(
                        opt.clear_qubits,
                        [e for e in range(i, i + opt.clear_span)])
                    new_operations = self.post_clean_up(
                        cast(Tuple[ops.Operation], opt.new_operations))

                    flat_new_operations = tuple(
                        ops.flatten_to_ops(new_operations))

                    new_qubits = set()
                    for flat_op in flat_new_operations:
                        for q in flat_op.qubits:
                            new_qubits.add(q)

                    if not new_qubits.issubset(set(opt.clear_qubits)):
                        raise ValueError(
                            'New operations in PointOptimizer should not act on new'
                            ' qubits.')
                    moment_new_ops[i].extend(flat_new_operations)
        frontier = 0
        for i in range(circuit_len):
            new_frontier = circuit.insert(frontier, moment_new_ops[i],
                                          InsertStrategy.EARLIEST_AFTER)
            if frontier < new_frontier:
                frontier = new_frontier
Exemplo n.º 17
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))
Exemplo n.º 18
0
    def _base_iterator(
        self,
        circuit: circuits.Circuit,
        qubit_order: ops.QubitOrderOrList,
        initial_state: Union[np.ndarray, 'cirq.STATE_VECTOR_LIKE'],
        all_measurements_are_terminal=False,
        is_raw_state=False,
    ) -> Iterator['DensityMatrixStepResult']:
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        qid_shape = protocols.qid_shape(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        initial_matrix = (qis.to_valid_density_matrix(initial_state,
                                                      len(qid_shape),
                                                      qid_shape=qid_shape,
                                                      dtype=self._dtype)
                          if not is_raw_state else initial_state)
        if np.may_share_memory(initial_matrix, initial_state):
            initial_matrix = initial_matrix.copy()

        if len(circuit) == 0:
            yield DensityMatrixStepResult(initial_matrix, {}, qubit_map,
                                          self._dtype)
            return

        tensor = initial_matrix.reshape(qid_shape * 2)
        sim_state = act_on_density_matrix_args.ActOnDensityMatrixArgs(
            target_tensor=tensor,
            available_buffer=[np.empty_like(tensor) for _ in range(3)],
            axes=[],
            qid_shape=qid_shape,
            prng=self._prng,
            log_of_measurement_results={},
        )

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        measured = collections.defaultdict(
            bool)  # type: Dict[Tuple[cirq.Qid, ...], bool]
        for moment in noisy_moments:
            for op in flatten_to_ops(moment):
                # TODO: support more general measurements.
                # Github issue: https://github.com/quantumlib/Cirq/issues/3566
                if all_measurements_are_terminal and measured[op.qubits]:
                    continue
                if protocols.is_measurement(op):
                    measured[op.qubits] = True
                    if all_measurements_are_terminal:
                        continue
                    if self._ignore_measurement_results:
                        op = ops.phase_damp(1).on(*op.qubits)
                sim_state.axes = tuple(qubit_map[qubit] for qubit in op.qubits)
                protocols.act_on(op, sim_state)

            yield DensityMatrixStepResult(
                density_matrix=sim_state.target_tensor,
                measurements=dict(sim_state.log_of_measurement_results),
                qubit_map=qubit_map,
                dtype=self._dtype,
            )
            sim_state.log_of_measurement_results.clear()
Exemplo n.º 19
0
def decompose(
        val: TValue,
        *,
        intercepting_decomposer: Optional[OpDecomposer] = None,
        fallback_decomposer: Optional[OpDecomposer] = None,
        keep: Optional[Callable[['cirq.Operation'], bool]] = None,
        on_stuck_raise: Union[None, Exception, Callable[[
            'cirq.Operation'
        ], Union[None, Exception]]] = _value_error_describing_bad_operation
) -> List['cirq.Operation']:
    """Recursively decomposes a value into `cirq.Operation`s meeting a criteria.

    Args:
        val: The value to decompose into operations.
        intercepting_decomposer: An optional method that is called before the
            default decomposer (the value's `_decompose_` method). If
            `intercepting_decomposer` is specified and returns a result that
            isn't `NotImplemented` or `None`, that result is used. Otherwise the
            decomposition falls back to the default decomposer.

            Note that `val` will be passed into `intercepting_decomposer`, even
            if `val` isn't a `cirq.Operation`.
        fallback_decomposer: An optional decomposition that used after the
            `intercepting_decomposer` and the default decomposer (the value's
            `_decompose_` method) both fail.
        keep: A predicate that determines if the initial operation or
            intermediate decomposed operations should be kept or else need to be
            decomposed further. If `keep` isn't specified, it defaults to "value
            can't be decomposed anymore".
        on_stuck_raise: If there is an operation that can't be decomposed and
            also can't be kept, `on_stuck_raise` is used to determine what error
            to raise. `on_stuck_raise` can either directly be an `Exception`, or
            a method that takes the problematic operation and returns an
            `Exception`. If `on_stuck_raise` is set to `None` or a method that
            returns `None`, undecomposable operations are simply silently kept.
            `on_stuck_raise` defaults to a `ValueError` describing the unwanted
            undecomposable operation.

    Returns:
        A list of operations that the given value was decomposed into. If
        `on_stuck_raise` isn't set to None, all operations in the list will
        satisfy the predicate specified by `keep`.

    Raises:
        TypeError:
            `val` isn't a `cirq.Operation` and can't be decomposed even once.
            (So it's not possible to return a list of operations.)

        ValueError:
            Default type of error raised if there's an undecomposable operation
            that doesn't satisfy the given `keep` predicate.

        TError:
            Custom type of error raised if there's an undecomposable operation
            that doesn't satisfy the given `keep` predicate.
    """

    if (on_stuck_raise is not _value_error_describing_bad_operation and
            keep is None):
        raise ValueError(
            "Must specify 'keep' if specifying 'on_stuck_raise', because it's "
            "not possible to get stuck if you don't have a criteria on what's "
            "acceptable to keep.")

    def try_op_decomposer(val: Any, decomposer: Optional[OpDecomposer]
                         ) -> DecomposeResult:
        if decomposer is None or not isinstance(val, ops.Operation):
            return None
        return decomposer(val)

    output = []
    queue: List[Any] = [val]
    while queue:
        item = queue.pop(0)

        if isinstance(item, ops.Operation) and keep is not None and keep(item):
            output.append(item)
            continue

        decomposed = try_op_decomposer(item, intercepting_decomposer)

        if decomposed is NotImplemented or decomposed is None:
            decomposed = decompose_once(item, default=None)

        if decomposed is NotImplemented or decomposed is None:
            decomposed = try_op_decomposer(item, fallback_decomposer)

        if decomposed is not NotImplemented and decomposed is not None:
            queue[:0] = ops.flatten_to_ops(decomposed)
            continue

        if not isinstance(item, ops.Operation) and isinstance(item, Iterable):
            queue[:0] = ops.flatten_to_ops(item)
            continue

        if keep is not None and on_stuck_raise is not None:
            if isinstance(on_stuck_raise, Exception):
                raise on_stuck_raise
            elif callable(on_stuck_raise):
                error = on_stuck_raise(item)
                if error is not None:
                    raise error

        output.append(item)

    return output
 def is_supported(self, op_tree: 'cirq.OP_TREE') -> bool:
     """Whether the given object contains only supported operations."""
     return all(self.is_supported_operation(op) for op in ops.flatten_to_ops(op_tree))