def _control_keys(self) -> FrozenSet['cirq.MeasurementKey']:
     keys = (frozenset() if not protocols.control_keys(self.circuit) else
             protocols.control_keys(self._mapped_single_loop()))
     if self.repeat_until is not None:
         keys |= frozenset(
             self.repeat_until.keys) - self._measurement_key_objs_()
     return keys
Exemple #2
0
 def _control_keys_(self) -> AbstractSet['cirq.MeasurementKey']:
     if self._cached_control_keys is None:
         keys = (frozenset() if not protocols.control_keys(self.circuit)
                 else protocols.control_keys(self._mapped_single_loop()))
         if self.repeat_until is not None:
             keys |= frozenset(
                 self.repeat_until.keys) - self._measurement_key_objs_()
         object.__setattr__(self, '_cached_control_keys', keys)
     return self._cached_control_keys  # type: ignore
Exemple #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
Exemple #4
0
    def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment':
        """Returns an equal moment, but with the given op added.

        Args:
            operation: The operation to append.

        Returns:
            The new moment.

        Raises:
            ValueError: If the operation given overlaps a current operation in the moment.
        """
        if any(q in self._qubits for q in operation.qubits):
            raise ValueError(f'Overlapping operations: {operation}')

        # Use private variables to facilitate a quick copy.
        m = Moment()
        m._operations = self._operations + (operation, )
        m._sorted_operations = None
        m._qubits = self._qubits.union(operation.qubits)
        m._qubit_to_op = {
            **self._qubit_to_op,
            **{q: operation
               for q in operation.qubits}
        }

        m._measurement_key_objs = self._measurement_key_objs_().union(
            protocols.measurement_key_objs(operation))
        m._control_keys = self._control_keys_().union(
            protocols.control_keys(operation))

        return m
Exemple #5
0
def _op_info_with_fallback(
    op: 'cirq.Operation', args: 'cirq.CircuitDiagramInfoArgs'
) -> 'cirq.CircuitDiagramInfo':
    info = protocols.circuit_diagram_info(op, args, None)
    rows: List[LabelEntity] = list(op.qubits)
    if args.label_map is not None:
        rows += protocols.measurement_key_objs(op) & args.label_map.keys()
        rows += protocols.control_keys(op) & args.label_map.keys()
    if info is not None:
        if max(1, len(rows)) != len(info.wire_symbols):
            raise ValueError(f'Wanted diagram info from {op!r} for {rows!r}) but got {info!r}')
        return info

    # Use the untagged operation's __str__.
    name = str(op.untagged)

    # Representation usually looks like 'gate(qubit1, qubit2, etc)'.
    # Try to cut off the qubit part, since that would be redundant.
    redundant_tail = f"({', '.join(str(e) for e in op.qubits)})"
    if name.endswith(redundant_tail):
        name = name[: -len(redundant_tail)]

    # Add tags onto the representation, if they exist
    if op.tags:
        name += f'{list(op.tags)}'

    # Include ordering in the qubit labels.
    symbols = (name,) + tuple(f'#{i + 1}' for i in range(1, len(op.qubits)))

    return protocols.CircuitDiagramInfo(wire_symbols=symbols)
Exemple #6
0
    def _commutes_(
        self,
        other: Any,
        *,
        atol: Union[int,
                    float] = 1e-8) -> Union[bool, NotImplementedType, None]:
        """Determine if this Operation commutes with the object"""
        if not isinstance(other, Operation):
            return NotImplemented

        self_keys = protocols.measurement_key_objs(self)
        other_keys = protocols.measurement_key_objs(other)
        if (not self_keys.isdisjoint(other_keys)
                or not protocols.control_keys(self).isdisjoint(other_keys)
                or not protocols.control_keys(other).isdisjoint(self_keys)):
            return False

        if hasattr(other, 'qubits') and set(self.qubits).isdisjoint(
                other.qubits):
            return True

        from cirq import circuits

        # Remove the classical controls to validate the quantum commutativity. This can be done
        # because during execution, the two operations will either both be run, in which case they
        # behave like the suboperations, so if the suboperations commute then these commute. Or
        # one of them is cold in which case it behaves like the identity, which always commutes.
        self_raw = self.without_classical_controls()
        other_raw = other.without_classical_controls()
        circuit12 = circuits.Circuit(self_raw, other_raw)
        circuit21 = circuits.Circuit(other_raw, self_raw)

        # Don't create gigantic matrices.
        shape = protocols.qid_shape_protocol.qid_shape(circuit12)
        if np.prod(shape, dtype=np.int64) > 2**10:
            return NotImplemented  # coverage: ignore

        m12 = protocols.unitary_protocol.unitary(circuit12, default=None)
        m21 = protocols.unitary_protocol.unitary(circuit21, default=None)
        if m12 is None or m21 is None:
            return NotImplemented

        return np.allclose(m12, m21, atol=atol)
Exemple #7
0
 def remove_op_from_moment(self, moment_index: int,
                           op: 'cirq.Operation') -> None:
     self.ops_by_index[moment_index].pop(op)
     for q in op.qubits:
         if self.qubit_indexes[q][-1] == moment_index:
             self.qubit_indexes[q].pop()
         else:
             self.qubit_indexes[q].remove(moment_index)
     for mkey in protocols.measurement_key_objs(op):
         self.mkey_indexes[mkey].remove(moment_index)
     for ckey in protocols.control_keys(op):
         self.ckey_indexes[ckey].remove(moment_index)
Exemple #8
0
 def add_op_to_moment(self, moment_index: int,
                      op: 'cirq.Operation') -> None:
     self.ops_by_index[moment_index][op] = 0
     for q in op.qubits:
         if moment_index > self.qubit_indexes[q][-1]:
             self.qubit_indexes[q].append(moment_index)
         else:
             bisect.insort(self.qubit_indexes[q], moment_index)
     for mkey in protocols.measurement_key_objs(op):
         bisect.insort(self.mkey_indexes[mkey], moment_index)
     for ckey in protocols.control_keys(op):
         bisect.insort(self.ckey_indexes[ckey], moment_index)
Exemple #9
0
    def get_mergeable_ops(
            self, op: 'cirq.Operation',
            op_qs: Set['cirq.Qid']) -> Tuple[int, List['cirq.Operation']]:
        # Find the index of previous moment which can be merged with `op`.
        idx = max([self.qubit_indexes[q][-1] for q in op_qs], default=-1)
        idx = max([idx] + [
            self.mkey_indexes[ckey][-1] for ckey in protocols.control_keys(op)
        ])
        idx = max([idx] + [
            self.ckey_indexes[mkey][-1]
            for mkey in protocols.measurement_key_objs(op)
        ])
        # Return the set of overlapping ops in moment with index `idx`.
        if idx == -1:
            return idx, []

        return idx, [
            left_op for left_op in self.ops_by_index[idx]
            if not op_qs.isdisjoint(left_op.qubits)
        ]
Exemple #10
0
    def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment':
        """Returns a new moment with the given contents added.

        Args:
            *contents: New operations to add to this moment.

        Returns:
            The new moment.

        Raises:
            ValueError: If the contents given overlaps a current operation in the moment.
        """
        flattened_contents = tuple(op_tree.flatten_to_ops(contents))

        m = Moment()
        # Use private variables to facilitate a quick copy.
        m._qubit_to_op = self._qubit_to_op.copy()
        qubits = set(self._qubits)
        for op in flattened_contents:
            if any(q in qubits for q in op.qubits):
                raise ValueError(f'Overlapping operations: {op}')
            qubits.update(op.qubits)
            for q in op.qubits:
                m._qubit_to_op[q] = op
        m._qubits = frozenset(qubits)

        m._operations = self._operations + flattened_contents
        m._sorted_operations = None
        m._measurement_key_objs = self._measurement_key_objs_().union(
            set(
                itertools.chain(*(protocols.measurement_key_objs(op)
                                  for op in flattened_contents))))
        m._control_keys = self._control_keys_().union(
            set(
                itertools.chain(*(protocols.control_keys(op)
                                  for op in flattened_contents))))

        return m
Exemple #11
0
 def _control_keys_(self) -> AbstractSet['cirq.MeasurementKey']:
     return protocols.control_keys(self.sub_operation)
Exemple #12
0
 def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']:
     if self._control_keys is None:
         self._control_keys = frozenset(k for op in self.operations
                                        for k in protocols.control_keys(op))
     return self._control_keys
Exemple #13
0
 def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']:
     local_keys: FrozenSet['cirq.MeasurementKey'] = frozenset(
         k for condition in self._conditions for k in condition.keys)
     return local_keys.union(protocols.control_keys(self._sub_operation))
 def _control_keys_(self) -> AbstractSet['cirq.MeasurementKey']:
     if not protocols.control_keys(self.circuit):
         return frozenset()
     return protocols.control_keys(self.mapped_circuit())