Ejemplo n.º 1
0
    def noisy_moment(self, moment: ops.Moment,
                     system_qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':
        moments: List[ops.Moment] = []

        if any([protocols.is_measurement(op.gate) for op in moment.operations
                ]):  # Add readout error before measurement gate
            p00 = self._noise_properties.p00
            p11 = self._noise_properties.p11
            measurement_qubits = [
                list(op.qubits)[0] for op in moment.operations
                if protocols.is_measurement(op.gate)
            ]
            if p00 is not None or p11 is not None:
                _apply_readout_noise(p00, p11, moments, measurement_qubits)
            moments.append(moment)
        else:
            moments.append(moment)
        if self._noise_properties.pauli_error is not None:  # Add depolarization error#
            duration = max(
                [get_duration_ns(op.gate) for op in moment.operations])
            pauli_error = self._noise_properties.pauli_error_from_depolarization(
                duration)
            _apply_depol_noise(pauli_error, moments, system_qubits)

        if self._noise_properties.t1_ns is not None:  # Add amplitude damping noise
            duration = max(
                [get_duration_ns(op.gate) for op in moment.operations])
            _apply_amplitude_damp_noise(duration, self._noise_properties.t1_ns,
                                        moments, system_qubits)
        return moments
Ejemplo n.º 2
0
    def noisy_moments(
            self, moments: Iterable['cirq.Moment'],
            system_qubits: Sequence['cirq.Qid']) -> Sequence['cirq.OP_TREE']:
        # Split multi-qubit measurements into single-qubit measurements.
        # These will be recombined after noise is applied.
        split_measure_moments = []
        multi_measurements = {}
        for moment in moments:
            split_measure_ops = []
            for op in moment:
                if not protocols.is_measurement(op):
                    split_measure_ops.append(op)
                    continue
                m_key = protocols.measurement_key_obj(op)
                multi_measurements[m_key] = op
                for q in op.qubits:
                    split_measure_ops.append(ops.measure(q, key=m_key))
            split_measure_moments.append(circuits.Moment(split_measure_ops))

        # Append PHYSICAL_GATE_TAG to non-virtual ops in the input circuit,
        # using `self.virtual_predicate` to determine virtuality.
        new_moments = []
        for moment in split_measure_moments:
            virtual_ops = {op for op in moment if self.virtual_predicate(op)}
            physical_ops = [
                op.with_tags(PHYSICAL_GATE_TAG) for op in moment
                if op not in virtual_ops
            ]
            # Both physical and virtual operations remain in the circuit, but
            # only ops with PHYSICAL_GATE_TAG will receive noise.
            if virtual_ops:
                # Only subclasses will trigger this case.
                new_moments.append(
                    circuits.Moment(virtual_ops))  # coverage: ignore
            if physical_ops:
                new_moments.append(circuits.Moment(physical_ops))

        split_measure_circuit = circuits.Circuit(new_moments)

        # Add noise from each noise model. The PHYSICAL_GATE_TAGs added
        # previously allow noise models to distinguish physical gates from
        # those added by other noise models.
        noisy_circuit = split_measure_circuit.copy()
        for model in self.noise_models:
            noisy_circuit = noisy_circuit.with_noise(model)

        # Recombine measurements.
        final_moments = []
        for moment in noisy_circuit:
            combined_measure_ops = []
            restore_keys = set()
            for op in moment:
                if not protocols.is_measurement(op):
                    combined_measure_ops.append(op)
                    continue
                restore_keys.add(protocols.measurement_key_obj(op))
            for key in restore_keys:
                combined_measure_ops.append(multi_measurements[key])
            final_moments.append(circuits.Moment(combined_measure_ops))
        return final_moments
Ejemplo n.º 3
0
def find_terminal_measurements(
    circuit: 'cirq.AbstractCircuit',
) -> List[Tuple[int, 'cirq.Operation']]:
    """Finds all terminal measurements in the given circuit.

    A measurement is terminal if there are no other operations acting on the measured qubits
    after the measurement operation occurs in the circuit.

    Args:
        circuit: The circuit to find terminal measurements in.

    Returns:
        List of terminal measurements, each specified as (moment_index, measurement_operation).
    """

    open_qubits: Set['cirq.Qid'] = set(circuit.all_qubits())
    seen_control_keys: Set['cirq.MeasurementKey'] = set()
    terminal_measurements: List[Tuple[int, 'cirq.Operation']] = []
    for i in range(len(circuit) - 1, -1, -1):
        moment = circuit[i]
        for q in open_qubits:
            op = moment.operation_at(q)
            if (
                op is not None
                and open_qubits.issuperset(op.qubits)
                and protocols.is_measurement(op)
                and not (seen_control_keys & protocols.measurement_key_objs(op))
            ):
                terminal_measurements.append((i, op))
        open_qubits -= moment.qubits
        seen_control_keys |= protocols.control_keys(moment)
        if not open_qubits:
            break
    return terminal_measurements
Ejemplo 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()
Ejemplo n.º 5
0
    def repeat(
        self,
        repetitions: INT_TYPE,
    ) -> 'CircuitOperation':
        """Returns a copy of this operation repeated 'repetitions' times.

        Args:
            repetitions: Number of times this operation should repeat. This
                is multiplied with any pre-existing repetitions.

        Returns:
            A copy of this operation repeated 'repetitions' times.

        Raises:
            TypeError: `repetitions` is not an integer value.
            NotImplementedError: The operation contains measurements and
                cannot have repetitions.
        """
        if not isinstance(repetitions, (int, np.integer)):
            raise TypeError('Only integer repetitions are allowed.')
        if repetitions == 1:
            # As CircuitOperation is immutable, this can safely return the original.
            return self
        repetitions = int(repetitions)
        if protocols.is_measurement(self.circuit):
            raise NotImplementedError(
                'Loops over measurements are not supported.')
        return self.replace(repetitions=self.repetitions * repetitions)
Ejemplo n.º 6
0
    def _run(self, circuit: circuits.Circuit,
             param_resolver: study.ParamResolver,
             repetitions: int) -> Dict[str, np.ndarray]:
        """See definition in `cirq.SimulatesSamples`."""
        if self._ignore_measurement_results:
            raise ValueError(
                "run() is not supported when ignore_measurement_results = True"
            )

        param_resolver = param_resolver or study.ParamResolver({})
        resolved_circuit = protocols.resolve_parameters(
            circuit, param_resolver)
        check_all_resolved(resolved_circuit)
        qubits = tuple(sorted(resolved_circuit.all_qubits()))
        act_on_args = self._create_act_on_args(0, qubits)

        prefix, general_suffix = split_into_matching_protocol_then_general(
            resolved_circuit, lambda op: not protocols.is_measurement(op))
        step_result = None
        for step_result in self._core_iterator(
                circuit=prefix,
                sim_state=act_on_args,
        ):
            pass
        assert step_result is not None

        if general_suffix.are_all_measurements_terminal() and not any(
                general_suffix.findall_operations(
                    lambda op: isinstance(op, circuits.CircuitOperation))):
            return self._run_sweep_sample(general_suffix, repetitions,
                                          act_on_args)
        return self._run_sweep_repeat(general_suffix, repetitions, act_on_args)
Ejemplo n.º 7
0
    def _run(self, circuit: circuits.Circuit,
             param_resolver: study.ParamResolver,
             repetitions: int) -> Dict[str, np.ndarray]:
        """See definition in `cirq.SimulatesSamples`."""
        param_resolver = param_resolver or study.ParamResolver({})
        resolved_circuit = protocols.resolve_parameters(
            circuit, param_resolver)
        check_all_resolved(resolved_circuit)
        qubit_order = sorted(resolved_circuit.all_qubits())

        prefix, general_suffix = split_into_matching_protocol_then_general(
            resolved_circuit, lambda op: not protocols.is_measurement(op))
        step_result = None
        for step_result in self._base_iterator(
                circuit=prefix,
                qubit_order=qubit_order,
                initial_state=0,
        ):
            pass
        assert step_result is not None

        intermediate_state = step_result._density_matrix
        if general_suffix.are_all_measurements_terminal() and not any(
                general_suffix.findall_operations(
                    lambda op: isinstance(op, circuits.CircuitOperation))):
            return self._run_sweep_sample(general_suffix, repetitions,
                                          qubit_order, intermediate_state)
        return self._run_sweep_repeat(general_suffix, repetitions, qubit_order,
                                      intermediate_state)
Ejemplo n.º 8
0
 def _with_measurement_key_mapping_(self, key_map: Dict[str, str]):
     return Moment(
         protocols.with_measurement_key_mapping(op, key_map)
         if protocols.is_measurement(op)
         else op
         for op in self.operations
     )
Ejemplo n.º 9
0
 def defer(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     if op in terminal_measurements:
         return op
     gate = op.gate
     if isinstance(gate, ops.MeasurementGate):
         key = value.MeasurementKey.parse_serialized(gate.key)
         targets = [_MeasurementQid(key, q) for q in op.qubits]
         measurement_qubits[key] = targets
         cxs = [ops.CX(q, target) for q, target in zip(op.qubits, targets)]
         xs = [ops.X(targets[i]) for i, b in enumerate(gate.full_invert_mask()) if b]
         return cxs + xs
     elif protocols.is_measurement(op):
         return [defer(op, None) for op in protocols.decompose_once(op)]
     elif op.classical_controls:
         controls = []
         for c in op.classical_controls:
             if isinstance(c, value.KeyCondition):
                 if c.key not in measurement_qubits:
                     raise ValueError(f'Deferred measurement for key={c.key} not found.')
                 qubits = measurement_qubits[c.key]
                 if len(qubits) != 1:
                     # TODO: Multi-qubit conditions require
                     # https://github.com/quantumlib/Cirq/issues/4512
                     # Remember to update docstring above once this works.
                     raise ValueError('Only single qubit conditions are allowed.')
                 controls.extend(qubits)
             else:
                 raise ValueError('Only KeyConditions are allowed.')
         return op.without_classical_controls().controlled_by(
             *controls, control_values=[tuple(range(1, q.dimension)) for q in controls]
         )
     return op
Ejemplo n.º 10
0
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']):
    seen: Set[str] = set()
    for op in operations:
        if protocols.is_measurement(op):
            key = protocols.measurement_key(op)
            if key in seen:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen.add(key)
Ejemplo n.º 11
0
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']):
    """Raises an error if a measurement key is repeated in the given set of Operations."""
    seen_keys: Set[str] = set()
    for op in operations:
        if protocols.is_measurement(op):
            key = protocols.measurement_key(op)
            if key in seen_keys:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen_keys.add(key)
Ejemplo n.º 12
0
 def optimize_circuit(self, circuit: _circuit.Circuit) -> None:
     deletions: List[Tuple[int, ops.Operation]] = []
     for moment_index, moment in enumerate(circuit):
         for op in moment.operations:
             if protocols.is_measurement(op):
                 continue
             if protocols.trace_distance_bound(op) <= self.tolerance:
                 deletions.append((moment_index, op))
     circuit.batch_remove(deletions)
Ejemplo n.º 13
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()
Ejemplo n.º 14
0
    def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit':
        """Applies all maps to the contained circuit and returns the result.

        Args:
            deep: If true, this will also call mapped_circuit on any
                CircuitOperations this object contains.

        Returns:
            The contained circuit with all other member variables (repetitions,
            qubit mapping, parameterization, etc.) applied to it. This behaves
            like `cirq.decompose(self)`, but preserving moment structure.
        """
        circuit = self.circuit.unfreeze()
        circuit = circuit.transform_qubits(lambda q: self.qubit_map.get(q, q))
        if self.repetitions < 0:
            circuit = circuit**-1
        has_measurements = protocols.is_measurement(circuit)
        if has_measurements:
            circuit = protocols.with_measurement_key_mapping(
                circuit, self.measurement_key_map)
        circuit = protocols.resolve_parameters(circuit,
                                               self.param_resolver,
                                               recursive=False)
        if deep:

            def map_deep(op: 'cirq.Operation') -> 'cirq.OP_TREE':
                return op.mapped_circuit(
                    deep=True) if isinstance(op, CircuitOperation) else op

            if self.repetition_ids is None:
                return circuit.map_operations(map_deep)
            if not has_measurements:
                return circuit.map_operations(map_deep) * abs(self.repetitions)

            # Path must be constructed from the top down.
            rekeyed_circuit = circuits.Circuit(
                protocols.with_key_path(circuit, self.parent_path + (rep, ))
                for rep in self.repetition_ids)
            return rekeyed_circuit.map_operations(map_deep)

        if self.repetition_ids is None:
            return circuit
        if not has_measurements:
            return circuit * abs(self.repetitions)

        def rekey_op(op: 'cirq.Operation', rep: str):
            """Update measurement keys in `op` to include repetition ID `rep`."""
            rekeyed_op = protocols.with_key_path(op,
                                                 self.parent_path + (rep, ))
            if rekeyed_op is NotImplemented:
                return op
            return rekeyed_op

        return circuits.Circuit(
            circuit.map_operations(lambda op: rekey_op(op, rep))
            for rep in self.repetition_ids)
Ejemplo n.º 15
0
    def __post_init__(self):
        if not isinstance(self.circuit, circuits.FrozenCircuit):
            raise TypeError(
                f'Expected circuit of type FrozenCircuit, got: {type(self.circuit)!r}'
            )

        # Ensure that the circuit is invertible if the repetitions are negative.
        if self.repetitions < 0:
            try:
                protocols.inverse(self.circuit.unfreeze())
            except TypeError:
                raise ValueError(
                    f'repetitions are negative but the circuit is not invertible'
                )

        # Initialize repetition_ids to default, if unspecified. Else, validate their length.
        loop_size = abs(self.repetitions)
        if not self.repetition_ids:
            object.__setattr__(self, 'repetition_ids',
                               self._default_repetition_ids())
        elif len(self.repetition_ids) != loop_size:
            raise ValueError(
                f'Expected repetition_ids to be a list of length {loop_size}, '
                f'got: {self.repetition_ids}')

        # Disallow mapping to keys containing the `MEASUREMENT_KEY_SEPARATOR`
        for mapped_key in self.measurement_key_map.values():
            if MEASUREMENT_KEY_SEPARATOR in mapped_key:
                raise ValueError(
                    f'Mapping to invalid key: {mapped_key}. "{MEASUREMENT_KEY_SEPARATOR}" '
                    'is not allowed for measurement keys in a CircuitOperation'
                )

        # Validate the keys for all direct child measurements. They are not allowed to contain
        # `MEASUREMENT_KEY_SEPARATOR`
        for _, op in self.circuit.findall_operations(lambda op: not isinstance(
                op, CircuitOperation) and protocols.is_measurement(op)):
            for key in protocols.measurement_keys(op):
                key = self.measurement_key_map.get(key, key)
                if MEASUREMENT_KEY_SEPARATOR in key:
                    raise ValueError(
                        f'Measurement {op} found to have invalid key: {key}. '
                        f'"{MEASUREMENT_KEY_SEPARATOR}" is not allowed for measurement keys '
                        'in a CircuitOperation. Consider remapping the key using '
                        '`measurement_key_map` in the CircuitOperation constructor.'
                    )

        # Disallow qid mapping dimension conflicts.
        for q, q_new in self.qubit_map.items():
            if q_new.dimension != q.dimension:
                raise ValueError(
                    f'Qid dimension conflict.\nFrom qid: {q}\nTo qid: {q_new}')

        # Ensure that param_resolver is converted to an actual ParamResolver.
        object.__setattr__(self, 'param_resolver',
                           study.ParamResolver(self.param_resolver))
Ejemplo n.º 16
0
def _homogeneous_moment_is_measurements(moment: 'cirq.Moment') -> bool:
    """Whether the moment is nothing but measurement gates.

    If a moment is a mixture of measurement and non-measurement gates
    this will throw a ValueError.
    """
    cases = {protocols.is_measurement(gate) for gate in moment}
    if len(cases) == 2:
        raise ValueError("Moment must be homogeneous: all measurements or all operations.")
    return True in cases
Ejemplo n.º 17
0
 def is_supported_operation(op: 'cirq.Operation') -> bool:
     """Checks whether given operation can be simulated by this simulator."""
     if protocols.is_measurement(op): return True
     if isinstance(op, GlobalPhaseOperation): return True
     if not protocols.has_unitary(op): return False
     u = cirq.unitary(op)
     if u.shape == (2, 2):
         return not SingleQubitCliffordGate.from_unitary(u) is None
     else:
         return op.gate in [cirq.CNOT, cirq.CZ]
Ejemplo n.º 18
0
 def _decompose_(self) -> 'cirq.OP_TREE':
     result = self.circuit.unfreeze()
     result = result.transform_qubits(lambda q: self.qubit_map.get(q, q))
     if self.repetitions < 0:
         result = result**-1
     result = protocols.with_measurement_key_mapping(
         result, self.measurement_key_map)
     result = protocols.resolve_parameters(result,
                                           self.param_resolver,
                                           recursive=False)
     # repetition_ids don't need to be taken into account if the circuit has no measurements
     # or if repetition_ids are unset.
     if self.repetition_ids is None or not protocols.is_measurement(result):
         return list(result.all_operations()) * abs(self.repetitions)
     # If it's a measurement circuit with repetitions/repetition_ids, prefix the repetition_ids
     # to measurements. Details at https://tinyurl.com/measurement-repeated-circuitop.
     ops = []  # type: List[cirq.Operation]
     for parent_id in self.repetition_ids:
         for op in result.all_operations():
             if isinstance(op, CircuitOperation):
                 # For a CircuitOperation, prefix the current repetition_id to the children
                 # repetition_ids.
                 ops.append(
                     op.with_repetition_ids(
                         # If `op.repetition_ids` is None, this will return `[parent_id]`.
                         cartesian_product_of_string_lists(
                             [parent_id], op.repetition_ids)))
             elif protocols.is_measurement(op):
                 # For a non-CircuitOperation measurement, prefix the current repetition_id
                 # to the children measurement keys. Implemented by creating a mapping and
                 # using the with_measurement_key_mapping protocol.
                 ops.append(
                     protocols.with_measurement_key_mapping(
                         op,
                         key_map={
                             key:
                             f'{MEASUREMENT_KEY_SEPARATOR.join([parent_id, key])}'
                             for key in protocols.measurement_keys(op)
                         },
                     ))
             else:
                 ops.append(op)
     return ops
def _strat_act_on_state_vector_from_channel(
        action: Any, args: 'cirq.StateVectorSimulationState',
        qubits: Sequence['cirq.Qid']) -> bool:
    index = args._state.apply_channel(action, args.get_axes(qubits), args.prng)
    if index is None:
        return NotImplemented
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Ejemplo n.º 20
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()
Ejemplo n.º 21
0
def _needs_trajectories(circuit: circuits.Circuit) -> bool:
    """Checks if the circuit requires trajectory simulation."""
    for op in circuit.all_operations():
        test_op = (op if not protocols.is_parameterized(op) else
                   protocols.resolve_parameters(
                       op,
                       {param: 1
                        for param in protocols.parameter_names(op)}))
        if not (protocols.has_unitary(test_op)
                or protocols.is_measurement(test_op)):
            return True
    return False
Ejemplo n.º 22
0
    def noisy_moment(self, moment: 'cirq.Moment',
                     system_qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':
        if not moment.operations:
            return [moment]
        if self.require_physical_tag:
            physical_ops = [PHYSICAL_GATE_TAG in op.tags for op in moment]
            if any(physical_ops):
                if not all(physical_ops):
                    raise ValueError(
                        "Moments are expected to be all physical or all virtual ops, "
                        f"but found {moment.operations}")
            else:
                # Only moments with physical operations should have noise.
                return [moment]

        noise_ops: List['cirq.Operation'] = []
        # Some devices (including Google hardware) require that all gates have
        # the same duration, but this does not. Instead, each moment is assumed
        # to be as long as the longest gate it contains.
        moment_ns: float = 0
        for op in moment:
            op_duration: Optional[float] = None
            for key, duration in self.gate_durations_ns.items():
                if not issubclass(type(op.gate), key):
                    continue  # gate type doesn't match
                # TODO: remove assumption of same time across qubits
                op_duration = duration
                break
            if op_duration is None and isinstance(op.gate, ops.WaitGate):
                # special case for wait gates if not predefined
                nanos = op.gate.duration.total_nanos()
                if isinstance(nanos, sympy.Expr):
                    raise ValueError('Symbolic wait times are not supported')
                op_duration = nanos
            if op_duration is not None:
                moment_ns = max(moment_ns, op_duration)

        if moment_ns == 0:
            return [moment]

        for qubit in system_qubits:
            qubit_op = moment.operation_at(qubit)
            if self.skip_measurements and protocols.is_measurement(qubit_op):
                continue
            rates = self.rate_matrix_GHz[qubit] * moment_ns
            kraus_ops = _kraus_ops_from_rates(tuple(rates.reshape(-1)),
                                              rates.shape)
            noise_ops.append(ops.KrausChannel(kraus_ops).on(qubit))
        if not noise_ops:
            return [moment]
        output = [moment, moment_module.Moment(noise_ops)]
        return output[::-1] if self._prepend else output
Ejemplo n.º 23
0
    def intercept_decompose_func(self, op: ops.Operation) -> ops.OP_TREE:
        # Drop measurements.
        if protocols.is_measurement(op):
            return []

        # Immediately completely decompose two qubit unitary operations.
        if len(op.qubits) == 2:
            m = protocols.unitary(op, None)
            if m is not None:
                return optimizers.two_qubit_matrix_to_operations(
                    op.qubits[0], op.qubits[1], mat=m, allow_partial_czs=False)

        # Fallback to default.
        return NotImplemented
Ejemplo n.º 24
0
def validate_all_measurements(moment: 'cirq.Moment') -> bool:
    """Ensures that the moment is homogenous and returns whether all ops are measurement gates.

    Args:
        moment: the moment to be checked
    Returns:
        bool: True if all operations are measurements, False if none of them are
    Raises:
        ValueError: If a moment is a mixture of measurement and non-measurement gates.
    """
    cases = {protocols.is_measurement(gate) for gate in moment}
    if len(cases) == 2:
        raise ValueError("Moment must be homogeneous: all measurements or all operations.")
    return True in cases
Ejemplo n.º 25
0
def _strat_act_on_state_vector_from_channel(
        action: Any, args: 'cirq.ActOnStateVectorArgs',
        qubits: Sequence['cirq.Qid']) -> bool:
    kraus_operators = protocols.kraus(action, default=None)
    if kraus_operators is None:
        return NotImplemented

    def prepare_into_buffer(k: int):
        linalg.targeted_left_multiply(
            left_matrix=kraus_tensors[k],
            right_target=args.target_tensor,
            target_axes=args.get_axes(qubits),
            out=args.available_buffer,
        )

    shape = protocols.qid_shape(action)
    kraus_tensors = [
        e.reshape(shape * 2).astype(args.target_tensor.dtype)
        for e in kraus_operators
    ]
    p = args.prng.random()
    weight = None
    fallback_weight = 0
    fallback_weight_index = 0
    for index in range(len(kraus_tensors)):
        prepare_into_buffer(index)
        weight = np.linalg.norm(args.available_buffer)**2

        if weight > fallback_weight:
            fallback_weight_index = index
            fallback_weight = weight

        p -= weight
        if p < 0:
            break

    assert weight is not None, "No Kraus operators"
    if p >= 0 or weight == 0:
        # Floating point error resulted in a malformed sample.
        # Fall back to the most likely case.
        prepare_into_buffer(fallback_weight_index)
        weight = fallback_weight
        index = fallback_weight_index

    args.available_buffer /= np.sqrt(weight)
    args.swap_target_tensor_for(args.available_buffer)
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Ejemplo n.º 26
0
    def _run(self, circuit: circuits.Circuit,
             param_resolver: study.ParamResolver,
             repetitions: int) -> Dict[str, np.ndarray]:
        """See definition in `cirq.SimulatesSamples`."""
        param_resolver = param_resolver or study.ParamResolver({})
        resolved_circuit = protocols.resolve_parameters(
            circuit, param_resolver)
        check_all_resolved(resolved_circuit)

        _, general_suffix = split_into_matching_protocol_then_general(
            resolved_circuit, lambda op: not protocols.is_measurement(op))
        if general_suffix.are_all_measurements_terminal() and not any(
                general_suffix.findall_operations(
                    lambda op: isinstance(op, circuits.CircuitOperation))):
            return self._run_sweep_sample(resolved_circuit, repetitions)
        return self._run_sweep_repeat(resolved_circuit, repetitions)
Ejemplo n.º 27
0
    def _base_iterator(
            self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
            initial_state: int
    ) -> Iterator['cirq.CliffordSimulatorStepResult']:
        """Iterator over CliffordSimulatorStepResult 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.


        Yields:
            CliffordStepResult 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 CliffordSimulatorStepResult(measurements={},
                                              state=CliffordState(
                                                  qubit_map,
                                                  initial_state=initial_state))
        else:
            state = CliffordState(qubit_map, initial_state=initial_state)

            for moment in circuit:
                measurements = collections.defaultdict(
                    list)  # type: Dict[str, List[np.ndarray]]

                for op in moment:
                    print(type(op))
                    if protocols.has_unitary(op):
                        state.apply_unitary(op)
                    elif protocols.is_measurement(op):
                        key = protocols.measurement_key(op)
                        measurements[key].extend(
                            state.perform_measurement(op.qubits))

                yield CliffordSimulatorStepResult(measurements=measurements,
                                                  state=state)
Ejemplo n.º 28
0
def _strat_act_on_state_vector_from_mixture(
        action: Any, args: 'cirq.ActOnStateVectorArgs',
        qubits: Sequence['cirq.Qid']) -> bool:
    mixture = protocols.mixture(action, default=None)
    if mixture is None:
        return NotImplemented
    probabilities, unitaries = zip(*mixture)

    index = args.prng.choice(range(len(unitaries)), p=probabilities)
    shape = protocols.qid_shape(action) * 2
    unitary = unitaries[index].astype(args.target_tensor.dtype).reshape(shape)
    linalg.targeted_left_multiply(unitary,
                                  args.target_tensor,
                                  args.get_axes(qubits),
                                  out=args.available_buffer)
    args.swap_target_tensor_for(args.available_buffer)
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Ejemplo n.º 29
0
 def _decompose_(self) -> 'cirq.OP_TREE':
     result = self.circuit.unfreeze()
     result = result.transform_qubits(lambda q: self.qubit_map.get(q, q))
     if self.repetitions < 0:
         result = result**-1
     result = protocols.with_measurement_key_mapping(
         result, self.measurement_key_map)
     result = protocols.resolve_parameters(result,
                                           self.param_resolver,
                                           recursive=False)
     # repetition_ids don't need to be taken into account if the circuit has no measurements
     # or if repetition_ids are unset.
     if self.repetition_ids is None or not protocols.is_measurement(result):
         return list(result.all_operations()) * abs(self.repetitions)
     # If it's a measurement circuit with repetitions/repetition_ids, prefix the repetition_ids
     # to measurements. Details at https://tinyurl.com/measurement-repeated-circuitop.
     ops = []  # type: List[cirq.Operation]
     for repetition_id in self.repetition_ids:
         path = self.parent_path + (repetition_id, )
         ops += protocols.with_key_path(result, path).all_operations()
     return ops
Ejemplo n.º 30
0
    def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit':
        """Applies all maps to the contained circuit and returns the result.

        Args:
            deep: If true, this will also call mapped_circuit on any
                CircuitOperations this object contains.

        Returns:
            The contained circuit with all other member variables (repetitions,
            qubit mapping, parameterization, etc.) applied to it. This behaves
            like `cirq.decompose(self)`, but preserving moment structure.
        """
        circuit = self.circuit.unfreeze()
        if self.qubit_map:
            circuit = circuit.transform_qubits(
                lambda q: self.qubit_map.get(q, q))
        if self.repetitions < 0:
            circuit = circuit**-1
        if self.measurement_key_map:
            circuit = protocols.with_measurement_key_mapping(
                circuit, self.measurement_key_map)
        if self.param_resolver:
            circuit = protocols.resolve_parameters(circuit,
                                                   self.param_resolver,
                                                   recursive=False)
        if self.repetition_ids:
            if not protocols.is_measurement(circuit):
                circuit = circuit * abs(self.repetitions)
            else:
                circuit = circuits.Circuit(
                    protocols.with_rescoped_keys(circuit, (rep, ))
                    for rep in self.repetition_ids)
        circuit = protocols.with_rescoped_keys(circuit,
                                               self.parent_path,
                                               bindable_keys=self.extern_keys)
        if deep:
            circuit = circuit.map_operations(lambda op: op.mapped_circuit(
                deep=True) if isinstance(op, CircuitOperation) else op)
        return circuit