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
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
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
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
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)
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)
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)
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)
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) ]
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
def _control_keys_(self) -> AbstractSet['cirq.MeasurementKey']: return protocols.control_keys(self.sub_operation)
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
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())