diff --git a/cirq-aqt/cirq_aqt/aqt_device.py b/cirq-aqt/cirq_aqt/aqt_device.py index 9209fedeaf4..c6a9a386bba 100644 --- a/cirq-aqt/cirq_aqt/aqt_device.py +++ b/cirq-aqt/cirq_aqt/aqt_device.py @@ -249,9 +249,9 @@ class AQTDevice(cirq.Device): def __init__( self, - measurement_duration: 'cirq.DURATION_LIKE', - twoq_gates_duration: 'cirq.DURATION_LIKE', - oneq_gates_duration: 'cirq.DURATION_LIKE', + measurement_duration: cirq.DURATION_LIKE, + twoq_gates_duration: cirq.DURATION_LIKE, + oneq_gates_duration: cirq.DURATION_LIKE, qubits: Iterable[cirq.LineQubit], ) -> None: """Initializes the description of an ion trap device. diff --git a/cirq-aqt/cirq_aqt/aqt_device_metadata.py b/cirq-aqt/cirq_aqt/aqt_device_metadata.py index 82137d379f5..43c0404c289 100644 --- a/cirq-aqt/cirq_aqt/aqt_device_metadata.py +++ b/cirq-aqt/cirq_aqt/aqt_device_metadata.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - """DeviceMetadata for ion trap device with mutually linked qubits placed on a line.""" from typing import Any, Iterable, Mapping @@ -28,10 +27,10 @@ class AQTDeviceMetadata(cirq.DeviceMetadata): def __init__( self, - qubits: Iterable['cirq.LineQubit'], - measurement_duration: 'cirq.DURATION_LIKE', - twoq_gates_duration: 'cirq.DURATION_LIKE', - oneq_gates_duration: 'cirq.DURATION_LIKE', + qubits: Iterable[cirq.LineQubit], + measurement_duration: cirq.DURATION_LIKE, + twoq_gates_duration: cirq.DURATION_LIKE, + oneq_gates_duration: cirq.DURATION_LIKE, ): """Create metadata object for AQTDevice. @@ -60,12 +59,12 @@ def __init__( ) @property - def gateset(self) -> 'cirq.Gateset': + def gateset(self) -> cirq.Gateset: """Returns the `cirq.Gateset` of supported gates on this device.""" return self._gateset @property - def gate_durations(self) -> Mapping['cirq.GateFamily', 'cirq.Duration']: + def gate_durations(self) -> Mapping[cirq.GateFamily, cirq.Duration]: """Get a dictionary of supported gate families and their gate operation durations. Use `duration_of` to obtain duration of a specific `cirq.GateOperation` instance. @@ -73,21 +72,21 @@ def gate_durations(self) -> Mapping['cirq.GateFamily', 'cirq.Duration']: return self._gate_durations @property - def measurement_duration(self) -> 'cirq.DURATION_LIKE': + def measurement_duration(self) -> cirq.DURATION_LIKE: """Return the maximum duration of the measurement operation.""" return self._measurement_duration @property - def oneq_gates_duration(self) -> 'cirq.DURATION_LIKE': + def oneq_gates_duration(self) -> cirq.DURATION_LIKE: """Return the maximum duration of an operation on one-qubit gates.""" return self._oneq_gates_duration @property - def twoq_gates_duration(self) -> 'cirq.DURATION_LIKE': + def twoq_gates_duration(self) -> cirq.DURATION_LIKE: """Return the maximum duration of an operation on two-qubit gates.""" return self._twoq_gates_duration - def duration_of(self, operation: 'cirq.Operation') -> 'cirq.DURATION_LIKE': + def duration_of(self, operation: cirq.Operation) -> cirq.DURATION_LIKE: """Return the maximum duration of the specified gate operation. Args: diff --git a/cirq-aqt/cirq_aqt/aqt_target_gateset.py b/cirq-aqt/cirq_aqt/aqt_target_gateset.py index 66766805650..0061f6e6d0d 100644 --- a/cirq-aqt/cirq_aqt/aqt_target_gateset.py +++ b/cirq-aqt/cirq_aqt/aqt_target_gateset.py @@ -42,7 +42,7 @@ def __init__(self): unroll_circuit_op=False, ) - def _decompose_single_qubit_operation(self, op: 'cirq.Operation', _: int) -> DecomposeResult: + def _decompose_single_qubit_operation(self, op: cirq.Operation, _: int) -> DecomposeResult: # unwrap tagged and circuit operations to get the actual operation opu = op.untagged opu = ( @@ -57,7 +57,7 @@ def _decompose_single_qubit_operation(self, op: 'cirq.Operation', _: int) -> Dec return [g.on(opu.qubits[0]) for g in gates] return NotImplemented - def _decompose_two_qubit_operation(self, op: 'cirq.Operation', _) -> DecomposeResult: + def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult: if cirq.has_unitary(op): return cirq.two_qubit_matrix_to_ion_operations( op.qubits[0], op.qubits[1], cirq.unitary(op) @@ -65,6 +65,6 @@ def _decompose_two_qubit_operation(self, op: 'cirq.Operation', _) -> DecomposeRe return NotImplemented @property - def postprocess_transformers(self) -> List['cirq.TRANSFORMER']: + def postprocess_transformers(self) -> List[cirq.TRANSFORMER]: """List of transformers which should be run after decomposing individual operations.""" return [cirq.drop_negligible_operations, cirq.drop_empty_moments] diff --git a/cirq-core/cirq/circuits/circuit.py b/cirq-core/cirq/circuits/circuit.py index 6b2595d036c..dc19c4baccf 100644 --- a/cirq-core/cirq/circuits/circuit.py +++ b/cirq-core/cirq/circuits/circuit.py @@ -19,6 +19,8 @@ Moment the Operations must all act on distinct Qubits. """ +from __future__ import annotations + import abc import enum import html @@ -146,7 +148,7 @@ class AbstractCircuit(abc.ABC): """ @classmethod - def from_moments(cls: Type[CIRCUIT_TYPE], *moments: Optional['cirq.OP_TREE']) -> CIRCUIT_TYPE: + def from_moments(cls: Type[CIRCUIT_TYPE], *moments: Optional[cirq.OP_TREE]) -> CIRCUIT_TYPE: """Create a circuit from moment op trees. Args: @@ -164,7 +166,7 @@ def from_moments(cls: Type[CIRCUIT_TYPE], *moments: Optional['cirq.OP_TREE']) -> return cls._from_moments(cls._make_moments(moments)) @staticmethod - def _make_moments(moments: Iterable[Optional['cirq.OP_TREE']]) -> Iterator['cirq.Moment']: + def _make_moments(moments: Iterable[Optional[cirq.OP_TREE]]) -> Iterator[cirq.Moment]: for m in moments: if isinstance(m, Moment): yield m @@ -175,7 +177,7 @@ def _make_moments(moments: Iterable[Optional['cirq.OP_TREE']]) -> Iterator['cirq @classmethod @abc.abstractmethod - def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable['cirq.Moment']) -> CIRCUIT_TYPE: + def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable[cirq.Moment]) -> CIRCUIT_TYPE: """Create a circuit from moments. This must be implemented by subclasses. It provides a more efficient way @@ -188,18 +190,18 @@ def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable['cirq.Moment']) -> @property @abc.abstractmethod - def moments(self) -> Sequence['cirq.Moment']: + def moments(self) -> Sequence[cirq.Moment]: pass @abc.abstractmethod - def freeze(self) -> 'cirq.FrozenCircuit': + def freeze(self) -> cirq.FrozenCircuit: """Creates a FrozenCircuit from this circuit. If 'self' is a FrozenCircuit, the original object is returned. """ @abc.abstractmethod - def unfreeze(self, copy: bool = True) -> 'cirq.Circuit': + def unfreeze(self, copy: bool = True) -> cirq.Circuit: """Creates a Circuit from this circuit. Args: @@ -231,24 +233,24 @@ def __ne__(self, other) -> bool: def __len__(self) -> int: return len(self.moments) - def __iter__(self) -> Iterator['cirq.Moment']: + def __iter__(self) -> Iterator[cirq.Moment]: return iter(self.moments) - def _decompose_(self) -> 'cirq.OP_TREE': + def _decompose_(self) -> cirq.OP_TREE: """See `cirq.SupportsDecompose`.""" return self.all_operations() # pylint: disable=function-redefined @overload - def __getitem__(self, key: int) -> 'cirq.Moment': + def __getitem__(self, key: int) -> cirq.Moment: pass @overload - def __getitem__(self, key: Tuple[int, 'cirq.Qid']) -> 'cirq.Operation': + def __getitem__(self, key: Tuple[int, cirq.Qid]) -> cirq.Operation: pass @overload - def __getitem__(self, key: Tuple[int, Iterable['cirq.Qid']]) -> 'cirq.Moment': + def __getitem__(self, key: Tuple[int, Iterable[cirq.Qid]]) -> cirq.Moment: pass @overload @@ -256,11 +258,11 @@ def __getitem__(self, key: slice) -> Self: pass @overload - def __getitem__(self, key: Tuple[slice, 'cirq.Qid']) -> Self: + def __getitem__(self, key: Tuple[slice, cirq.Qid]) -> Self: pass @overload - def __getitem__(self, key: Tuple[slice, Iterable['cirq.Qid']]) -> Self: + def __getitem__(self, key: Tuple[slice, Iterable[cirq.Qid]]) -> Self: pass def __getitem__(self, key): @@ -315,7 +317,7 @@ def _repr_html_(self) -> str: ) def _first_moment_operating_on( - self, qubits: Iterable['cirq.Qid'], indices: Iterable[int] + self, qubits: Iterable[cirq.Qid], indices: Iterable[int] ) -> Optional[int]: qubits = frozenset(qubits) for m in indices: @@ -325,7 +327,7 @@ def _first_moment_operating_on( def next_moment_operating_on( self, - qubits: Iterable['cirq.Qid'], + qubits: Iterable[cirq.Qid], start_moment_index: int = 0, max_distance: Optional[int] = None, ) -> Optional[int]: @@ -357,8 +359,8 @@ def next_moment_operating_on( ) def next_moments_operating_on( - self, qubits: Iterable['cirq.Qid'], start_moment_index: int = 0 - ) -> Dict['cirq.Qid', int]: + self, qubits: Iterable[cirq.Qid], start_moment_index: int = 0 + ) -> Dict[cirq.Qid, int]: """Finds the index of the next moment that touches each qubit. Args: @@ -380,7 +382,7 @@ def next_moments_operating_on( def prev_moment_operating_on( self, - qubits: Sequence['cirq.Qid'], + qubits: Sequence[cirq.Qid], end_moment_index: Optional[int] = None, max_distance: Optional[int] = None, ) -> Optional[int]: @@ -425,10 +427,10 @@ def prev_moment_operating_on( def reachable_frontier_from( self, - start_frontier: Dict['cirq.Qid', int], + start_frontier: Dict[cirq.Qid, int], *, - is_blocker: Callable[['cirq.Operation'], bool] = lambda op: False, - ) -> Dict['cirq.Qid', int]: + is_blocker: Callable[[cirq.Operation], bool] = lambda op: False, + ) -> Dict[cirq.Qid, int]: """Determines how far can be reached into a circuit under certain rules. The location L = (qubit, moment_index) is *reachable* if and only if the @@ -564,11 +566,11 @@ def reachable_frontier_from( where i is the moment index, q is the qubit, and end_frontier is the result of this method. """ - active: Set['cirq.Qid'] = set() + active: Set[cirq.Qid] = set() end_frontier = {} queue = BucketPriorityQueue[ops.Operation](drop_duplicate_entries=True) - def enqueue_next(qubit: 'cirq.Qid', moment: int) -> None: + def enqueue_next(qubit: cirq.Qid, moment: int) -> None: next_moment = self.next_moment_operating_on([qubit], moment) if next_moment is None: end_frontier[qubit] = max(len(self), start_frontier[qubit]) @@ -608,10 +610,10 @@ def enqueue_next(qubit: 'cirq.Qid', moment: int) -> None: def findall_operations_between( self, - start_frontier: Dict['cirq.Qid', int], - end_frontier: Dict['cirq.Qid', int], + start_frontier: Dict[cirq.Qid, int], + end_frontier: Dict[cirq.Qid, int], omit_crossing_operations: bool = False, - ) -> List[Tuple[int, 'cirq.Operation']]: + ) -> List[Tuple[int, cirq.Operation]]: """Finds operations between the two given frontiers. If a qubit is in `start_frontier` but not `end_frontier`, its end index @@ -656,9 +658,9 @@ def findall_operations_between( def findall_operations_until_blocked( self, - start_frontier: Dict['cirq.Qid', int], - is_blocker: Callable[['cirq.Operation'], bool] = lambda op: False, - ) -> List[Tuple[int, 'cirq.Operation']]: + start_frontier: Dict[cirq.Qid, int], + is_blocker: Callable[[cirq.Operation], bool] = lambda op: False, + ) -> List[Tuple[int, cirq.Operation]]: """Finds all operations until a blocking operation is hit. An operation is considered blocking if both of the following hold: @@ -760,7 +762,7 @@ def findall_operations_until_blocked( break return op_list - def operation_at(self, qubit: 'cirq.Qid', moment_index: int) -> Optional['cirq.Operation']: + def operation_at(self, qubit: cirq.Qid, moment_index: int) -> Optional[cirq.Operation]: """Finds the operation on a qubit within a moment, if any. Args: @@ -777,8 +779,8 @@ def operation_at(self, qubit: 'cirq.Qid', moment_index: int) -> Optional['cirq.O return self.moments[moment_index].operation_at(qubit) def findall_operations( - self, predicate: Callable[['cirq.Operation'], bool] - ) -> Iterable[Tuple[int, 'cirq.Operation']]: + self, predicate: Callable[[cirq.Operation], bool] + ) -> Iterable[Tuple[int, cirq.Operation]]: """Find the locations of all operations that satisfy a given condition. This returns an iterator of (index, operation) tuples where each @@ -799,7 +801,7 @@ def findall_operations( def findall_operations_with_gate_type( self, gate_type: Type[_TGate] - ) -> Iterable[Tuple[int, 'cirq.GateOperation', _TGate]]: + ) -> Iterable[Tuple[int, cirq.GateOperation, _TGate]]: """Find the locations of all gate operations of a given type. Args: @@ -832,7 +834,7 @@ def are_all_measurements_terminal(self) -> bool: """ return self.are_all_matches_terminal(protocols.is_measurement) - def are_all_matches_terminal(self, predicate: Callable[['cirq.Operation'], bool]) -> bool: + def are_all_matches_terminal(self, predicate: Callable[[cirq.Operation], bool]) -> bool: """Check whether all of the ops that satisfy a predicate are terminal. This method will transparently descend into any CircuitOperations this @@ -877,7 +879,7 @@ def are_any_measurements_terminal(self) -> bool: """ return self.are_any_matches_terminal(protocols.is_measurement) - def are_any_matches_terminal(self, predicate: Callable[['cirq.Operation'], bool]) -> bool: + def are_any_matches_terminal(self, predicate: Callable[[cirq.Operation], bool]) -> bool: """Check whether any of the ops that satisfy a predicate are terminal. This method will transparently descend into any CircuitOperations this @@ -915,12 +917,12 @@ def are_any_matches_terminal(self, predicate: Callable[['cirq.Operation'], bool] return True return False - def _has_op_at(self, moment_index: int, qubits: Iterable['cirq.Qid']) -> bool: + def _has_op_at(self, moment_index: int, qubits: Iterable[cirq.Qid]) -> bool: return 0 <= moment_index < len(self.moments) and self.moments[moment_index].operates_on( qubits ) - def all_qubits(self) -> FrozenSet['cirq.Qid']: + def all_qubits(self) -> FrozenSet[cirq.Qid]: """Returns the qubits acted upon by Operations in this circuit. Returns: FrozenSet of `cirq.Qid` objects acted on by all operations @@ -928,14 +930,14 @@ def all_qubits(self) -> FrozenSet['cirq.Qid']: """ return frozenset(q for m in self.moments for q in m.qubits) - def all_operations(self) -> Iterator['cirq.Operation']: + def all_operations(self) -> Iterator[cirq.Operation]: """Returns an iterator over the operations in the circuit. Returns: Iterator over `cirq.Operation` elements found in this circuit. """ return (op for moment in self for op in moment.operations) - def map_operations(self, func: Callable[['cirq.Operation'], 'cirq.OP_TREE']) -> Self: + def map_operations(self, func: Callable[[cirq.Operation], cirq.OP_TREE]) -> Self: """Applies the given function to all operations in this circuit. Args: @@ -946,14 +948,14 @@ def map_operations(self, func: Callable[['cirq.Operation'], 'cirq.OP_TREE']) -> each operation `op` replaced with `func(op)`. """ - def map_moment(moment: 'cirq.Moment') -> 'cirq.Circuit': + def map_moment(moment: cirq.Moment) -> cirq.Circuit: """Apply func to expand each op into a circuit, then zip up the circuits.""" return Circuit.zip(*[Circuit(func(op)) for op in moment]) return self._from_moments(m for moment in self for m in map_moment(moment)) def qid_shape( - self, qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT + self, qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT ) -> Tuple[int, ...]: """Get the qubit shapes of all qubits in this circuit. @@ -963,12 +965,12 @@ def qid_shape( qids = ops.QubitOrder.as_qubit_order(qubit_order).order_for(self.all_qubits()) return protocols.qid_shape(qids) - def all_measurement_key_objs(self) -> FrozenSet['cirq.MeasurementKey']: + def all_measurement_key_objs(self) -> FrozenSet[cirq.MeasurementKey]: return frozenset( key for op in self.all_operations() for key in protocols.measurement_key_objs(op) ) - def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']: + def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]: """Returns the set of all measurement keys in this circuit. Returns: FrozenSet of `cirq.MeasurementKey` objects that are @@ -1003,7 +1005,7 @@ def _with_key_path_prefix_(self, prefix: Tuple[str, ...]): ) def _with_rescoped_keys_( - self, path: Tuple[str, ...], bindable_keys: FrozenSet['cirq.MeasurementKey'] + self, path: Tuple[str, ...], bindable_keys: FrozenSet[cirq.MeasurementKey] ): moments = [] for moment in self.moments: @@ -1042,8 +1044,8 @@ def _unitary_(self) -> Union[np.ndarray, NotImplementedType]: def unitary( self, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, - qubits_that_should_be_present: Iterable['cirq.Qid'] = (), + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, + qubits_that_should_be_present: Iterable[cirq.Qid] = (), ignore_terminal_measurements: bool = True, dtype: Type[np.complexfloating] = np.complex128, ) -> np.ndarray: @@ -1119,12 +1121,12 @@ def _superoperator_(self) -> np.ndarray: def final_state_vector( self, *, - initial_state: 'cirq.STATE_VECTOR_LIKE' = 0, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + initial_state: cirq.STATE_VECTOR_LIKE = 0, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, ignore_terminal_measurements: bool = False, dtype: Type[np.complexfloating] = np.complex128, - param_resolver: 'cirq.ParamResolverOrSimilarType' = None, - seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + param_resolver: cirq.ParamResolverOrSimilarType = None, + seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None, ) -> np.ndarray: """Returns the state vector resulting from acting operations on a state. @@ -1182,7 +1184,7 @@ def to_text_diagram( transpose: bool = False, include_tags: bool = True, precision: Optional[int] = 3, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, ) -> str: """Returns text containing a diagram describing the circuit. @@ -1215,16 +1217,16 @@ def to_text_diagram_drawer( self, *, use_unicode_characters: bool = True, - qubit_namer: Optional[Callable[['cirq.Qid'], str]] = None, + qubit_namer: Optional[Callable[[cirq.Qid], str]] = None, transpose: bool = False, include_tags: bool = True, draw_moment_groups: bool = True, precision: Optional[int] = 3, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, get_circuit_diagram_info: Optional[ - Callable[['cirq.Operation', 'cirq.CircuitDiagramInfoArgs'], 'cirq.CircuitDiagramInfo'] + Callable[[cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo] ] = None, - ) -> 'cirq.TextDiagramDrawer': + ) -> cirq.TextDiagramDrawer: """Returns a TextDiagramDrawer with the circuit drawn into it. Args: @@ -1307,9 +1309,9 @@ def _is_parameterized_(self) -> bool: def _parameter_names_(self) -> AbstractSet[str]: return {name for op in self.all_operations() for name in protocols.parameter_names(op)} - def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) -> Self: + def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> Self: changed = False - resolved_moments: List['cirq.Moment'] = [] + resolved_moments: List[cirq.Moment] = [] for moment in self: resolved_moment = protocols.resolve_parameters(moment, resolver, recursive) if resolved_moment is not moment: @@ -1319,7 +1321,7 @@ def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) return self # pragma: no cover return self._from_moments(resolved_moments) - def _qasm_(self, args: Optional['cirq.QasmArgs'] = None) -> str: + def _qasm_(self, args: Optional[cirq.QasmArgs] = None) -> str: if args is None: output = self._to_qasm_output() else: @@ -1330,9 +1332,9 @@ def _to_qasm_output( self, header: Optional[str] = None, precision: int = 10, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, version: str = '2.0', - ) -> 'cirq.QasmOutput': + ) -> cirq.QasmOutput: """Returns a QASM object equivalent to the circuit. Args: @@ -1359,7 +1361,7 @@ def to_qasm( self, header: Optional[str] = None, precision: int = 10, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, version: str = '2.0', ) -> str: """Returns QASM equivalent to the circuit. @@ -1381,7 +1383,7 @@ def save_qasm( file_path: Union[str, bytes, int], header: Optional[str] = None, precision: int = 10, - qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, + qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT, ) -> None: """Save a QASM file equivalent to the circuit. @@ -1403,8 +1405,8 @@ def _from_json_dict_(cls, moments, **kwargs): return cls(moments, strategy=InsertStrategy.EARLIEST) def zip( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.AbstractCircuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.AbstractCircuit: """Combines operations from circuits in a moment-by-moment fashion. Moment k of the resulting circuit will have all operations from moment @@ -1479,8 +1481,8 @@ def zip( return result def concat_ragged( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.AbstractCircuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.AbstractCircuit: """Concatenates circuits, overlapping them if possible due to ragged edges. Starts with the first circuit (index 0), then iterates over the other @@ -1523,7 +1525,7 @@ def concat_ragged( # Allocate a buffer large enough to append and prepend all the circuits. pad_len = sum(len(c) for c in circuits) - n_acc - buffer: MutableSequence['cirq.Moment'] = [cirq.Moment()] * (pad_len * 2 + n_acc) + buffer: MutableSequence[cirq.Moment] = [cirq.Moment()] * (pad_len * 2 + n_acc) # Put the initial circuit in the center of the buffer. offset = pad_len @@ -1535,7 +1537,7 @@ def concat_ragged( return cirq.Circuit(buffer[offset : offset + n_acc]) - def get_independent_qubit_sets(self) -> List[Set['cirq.Qid']]: + def get_independent_qubit_sets(self) -> List[Set[cirq.Qid]]: """Divide circuit's qubits into independent qubit sets. Independent qubit sets are the qubit sets such that there are @@ -1614,17 +1616,17 @@ def factorize(self) -> Iterable[Self]: # moments. return (self._from_moments(m[qubits] for m in self.moments) for qubits in qubit_factors) - def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']: + def _control_keys_(self) -> FrozenSet[cirq.MeasurementKey]: controls = frozenset(k for op in self.all_operations() for k in protocols.control_keys(op)) return controls - protocols.measurement_key_objs(self) def _overlap_collision_time( - c1: Sequence['cirq.Moment'], c2: Sequence['cirq.Moment'], align: 'cirq.Alignment' + c1: Sequence[cirq.Moment], c2: Sequence[cirq.Moment], align: cirq.Alignment ) -> int: # Tracks the first used moment index for each qubit in c2. # Tracks the complementary last used moment index for each qubit in c1. - seen_times: Dict['cirq.Qid', int] = {} + seen_times: Dict[cirq.Qid, int] = {} # Start scanning from end of first and start of second. if align == Alignment.LEFT: @@ -1662,9 +1664,9 @@ def _overlap_collision_time( def _concat_ragged_helper( c1_offset: int, n1: int, - buf: MutableSequence['cirq.Moment'], - c2: Sequence['cirq.Moment'], - align: 'cirq.Alignment', + buf: MutableSequence[cirq.Moment], + c2: Sequence[cirq.Moment], + align: cirq.Alignment, ) -> Tuple[int, int]: n2 = len(c2) shift = _overlap_collision_time(buf[c1_offset : c1_offset + n1], c2, align) @@ -1755,7 +1757,7 @@ class Circuit(AbstractCircuit): """ def __init__( - self, *contents: 'cirq.OP_TREE', strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST + self, *contents: cirq.OP_TREE, strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST ) -> None: """Initializes a circuit. @@ -1771,13 +1773,13 @@ def __init__( circuit. """ self._placement_cache: Optional[_PlacementCache] = _PlacementCache() - self._moments: List['cirq.Moment'] = [] + self._moments: List[cirq.Moment] = [] # Implementation note: the following cached properties are set lazily and then # invalidated and reset to None in `self._mutated()`, which is called any time # `self._moments` is changed. - self._all_qubits: Optional[FrozenSet['cirq.Qid']] = None - self._frozen: Optional['cirq.FrozenCircuit'] = None + self._all_qubits: Optional[FrozenSet[cirq.Qid]] = None + self._frozen: Optional[cirq.FrozenCircuit] = None self._is_measurement: Optional[bool] = None self._is_parameterized: Optional[bool] = None self._parameter_names: Optional[AbstractSet[str]] = None @@ -1805,13 +1807,13 @@ def _mutated(self, *, preserve_placement_cache=False) -> None: self._placement_cache = None @classmethod - def _from_moments(cls, moments: Iterable['cirq.Moment']) -> 'Circuit': + def _from_moments(cls, moments: Iterable[cirq.Moment]) -> Circuit: new_circuit = Circuit() new_circuit._moments[:] = moments new_circuit._placement_cache = None return new_circuit - def _load_contents_with_earliest_strategy(self, contents: 'cirq.OP_TREE'): + def _load_contents_with_earliest_strategy(self, contents: cirq.OP_TREE): """Optimized algorithm to load contents quickly. The default algorithm appends operations one-at-a-time, letting them @@ -1835,8 +1837,8 @@ def _load_contents_with_earliest_strategy(self, contents: 'cirq.OP_TREE'): # We also maintain the dict from moment index to moments/ops that go into it, for use when # building the actual moments at the end. - op_lists_by_index: Dict[int, List['cirq.Operation']] = defaultdict(list) - moments_by_index: Dict[int, 'cirq.Moment'] = {} + op_lists_by_index: Dict[int, List[cirq.Operation]] = defaultdict(list) + moments_by_index: Dict[int, cirq.Moment] = {} # "mop" means current moment-or-operation for mop in ops.flatten_to_ops_or_moments(contents): @@ -1855,10 +1857,10 @@ def _load_contents_with_earliest_strategy(self, contents: 'cirq.OP_TREE'): else: self._moments.append(Moment(op_lists_by_index[i])) - def __copy__(self) -> 'cirq.Circuit': + def __copy__(self) -> cirq.Circuit: return self.copy() - def freeze(self) -> 'cirq.FrozenCircuit': + def freeze(self) -> cirq.FrozenCircuit: """Gets a frozen version of this circuit. Repeated calls to `.freeze()` will return the same FrozenCircuit @@ -1870,10 +1872,10 @@ def freeze(self) -> 'cirq.FrozenCircuit': self._frozen = FrozenCircuit._from_moments(self._moments) return self._frozen - def unfreeze(self, copy: bool = True) -> 'cirq.Circuit': + def unfreeze(self, copy: bool = True) -> cirq.Circuit: return self.copy() if copy else self - def all_qubits(self) -> FrozenSet['cirq.Qid']: + def all_qubits(self) -> FrozenSet[cirq.Qid]: if self._all_qubits is None: self._all_qubits = super().all_qubits() return self._all_qubits @@ -1893,7 +1895,7 @@ def _parameter_names_(self) -> AbstractSet[str]: self._parameter_names = super()._parameter_names_() return self._parameter_names - def copy(self) -> 'Circuit': + def copy(self) -> Circuit: """Return a copy of this circuit.""" copied_circuit = Circuit() copied_circuit._moments = self._moments[:] @@ -1902,11 +1904,11 @@ def copy(self) -> 'Circuit': # pylint: disable=function-redefined @overload - def __setitem__(self, key: int, value: 'cirq.Moment'): + def __setitem__(self, key: int, value: cirq.Moment): pass @overload - def __setitem__(self, key: slice, value: Iterable['cirq.Moment']): + def __setitem__(self, key: slice, value: Iterable[cirq.Moment]): pass def __setitem__(self, key, value): @@ -1967,7 +1969,7 @@ def __rmul__(self, repetitions: _INT_TYPE): return NotImplemented return self * int(repetitions) - def __pow__(self, exponent: int) -> 'cirq.Circuit': + def __pow__(self, exponent: int) -> cirq.Circuit: """A circuit raised to a power, only valid for exponent -1, the inverse. This will fail if anything other than -1 is passed to the Circuit by @@ -1991,22 +1993,22 @@ def __pow__(self, exponent: int) -> 'cirq.Circuit': __hash__ = None # type: ignore def concat_ragged( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.Circuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.Circuit: return AbstractCircuit.concat_ragged(*circuits, align=align).unfreeze(copy=False) concat_ragged.__doc__ = AbstractCircuit.concat_ragged.__doc__ def zip( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.Circuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.Circuit: return AbstractCircuit.zip(*circuits, align=align).unfreeze(copy=False) zip.__doc__ = AbstractCircuit.zip.__doc__ def transform_qubits( - self, qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']] - ) -> 'cirq.Circuit': + self, qubit_map: Union[Dict[cirq.Qid, cirq.Qid], Callable[[cirq.Qid], cirq.Qid]] + ) -> cirq.Circuit: """Returns the same circuit, but with different qubits. This function will return a new `Circuit` with the same gates but @@ -2053,7 +2055,7 @@ def transform_qubits( return Circuit(op_list) def earliest_available_moment( - self, op: 'cirq.Operation', *, end_moment_index: Optional[int] = None + self, op: cirq.Operation, *, end_moment_index: Optional[int] = None ) -> int: """Finds the index of the earliest (i.e. left most) moment which can accommodate `op`. @@ -2096,7 +2098,7 @@ def earliest_available_moment( last_available = k return last_available - def _can_add_op_at(self, moment_index: int, operation: 'cirq.Operation') -> bool: + def _can_add_op_at(self, moment_index: int, operation: cirq.Operation) -> bool: if not 0 <= moment_index < len(self._moments): return True @@ -2105,8 +2107,8 @@ def _can_add_op_at(self, moment_index: int, operation: 'cirq.Operation') -> bool def insert( self, index: int, - moment_or_operation_tree: 'cirq.OP_TREE', - strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST, + moment_or_operation_tree: cirq.OP_TREE, + strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST, ) -> int: """Inserts operations into the circuit. @@ -2146,7 +2148,7 @@ def insert( and not all( (strategy is InsertStrategy.EARLIEST and self._can_add_op_at(k, op)) or (k > 0 and self._can_add_op_at(k - 1, op)) - for op in cast(List['cirq.Operation'], batch) + for op in cast(List[cirq.Operation], batch) ) ): self._moments.insert(k, Moment()) @@ -2182,7 +2184,7 @@ def insert( self._mutated(preserve_placement_cache=True) return k - def insert_into_range(self, operations: 'cirq.OP_TREE', start: int, end: int) -> int: + def insert_into_range(self, operations: cirq.OP_TREE, start: int, end: int) -> int: """Writes operations inline into an area of the circuit. Args: @@ -2225,9 +2227,9 @@ def insert_into_range(self, operations: 'cirq.OP_TREE', start: int, end: int) -> def _push_frontier( self, - early_frontier: Dict['cirq.Qid', int], - late_frontier: Dict['cirq.Qid', int], - update_qubits: Optional[Iterable['cirq.Qid']] = None, + early_frontier: Dict[cirq.Qid, int], + late_frontier: Dict[cirq.Qid, int], + update_qubits: Optional[Iterable[cirq.Qid]] = None, ) -> Tuple[int, int]: """Inserts moments to separate two frontiers. @@ -2270,7 +2272,7 @@ def _push_frontier( return (0, 0) def _insert_operations( - self, operations: Sequence['cirq.Operation'], insertion_indices: Sequence[int] + self, operations: Sequence[cirq.Operation], insertion_indices: Sequence[int] ) -> None: """Inserts operations at the specified moments. Appends new moments if necessary. @@ -2290,18 +2292,15 @@ def _insert_operations( raise ValueError('operations and insertion_indices must have the same length.') self._moments += [Moment() for _ in range(1 + max(insertion_indices) - len(self))] self._mutated() - moment_to_ops: Dict[int, List['cirq.Operation']] = defaultdict(list) + moment_to_ops: Dict[int, List[cirq.Operation]] = defaultdict(list) for op_index, moment_index in enumerate(insertion_indices): moment_to_ops[moment_index].append(operations[op_index]) for moment_index, new_ops in moment_to_ops.items(): self._moments[moment_index] = self._moments[moment_index].with_operations(*new_ops) def insert_at_frontier( - self, - operations: 'cirq.OP_TREE', - start: int, - frontier: Optional[Dict['cirq.Qid', int]] = None, - ) -> Dict['cirq.Qid', int]: + self, operations: cirq.OP_TREE, start: int, frontier: Optional[Dict[cirq.Qid, int]] = None + ) -> Dict[cirq.Qid, int]: """Inserts operations inline at frontier. Args: @@ -2335,7 +2334,7 @@ def insert_at_frontier( return frontier - def batch_remove(self, removals: Iterable[Tuple[int, 'cirq.Operation']]) -> None: + def batch_remove(self, removals: Iterable[Tuple[int, cirq.Operation]]) -> None: """Removes several operations from a circuit. Args: @@ -2359,7 +2358,7 @@ def batch_remove(self, removals: Iterable[Tuple[int, 'cirq.Operation']]) -> None self._mutated() def batch_replace( - self, replacements: Iterable[Tuple[int, 'cirq.Operation', 'cirq.Operation']] + self, replacements: Iterable[Tuple[int, cirq.Operation, cirq.Operation]] ) -> None: """Replaces several operations in a circuit with new operations. @@ -2383,7 +2382,7 @@ def batch_replace( self._moments = copy._moments self._mutated() - def batch_insert_into(self, insert_intos: Iterable[Tuple[int, 'cirq.OP_TREE']]) -> None: + def batch_insert_into(self, insert_intos: Iterable[Tuple[int, cirq.OP_TREE]]) -> None: """Inserts operations into empty spaces in existing moments. If any of the insertions fails (due to colliding with an existing @@ -2404,7 +2403,7 @@ def batch_insert_into(self, insert_intos: Iterable[Tuple[int, 'cirq.OP_TREE']]) self._moments = copy._moments self._mutated() - def batch_insert(self, insertions: Iterable[Tuple[int, 'cirq.OP_TREE']]) -> None: + def batch_insert(self, insertions: Iterable[Tuple[int, cirq.OP_TREE]]) -> None: """Applies a batched insert operation to the circuit. Transparently handles the fact that earlier insertions may shift @@ -2441,8 +2440,8 @@ def batch_insert(self, insertions: Iterable[Tuple[int, 'cirq.OP_TREE']]) -> None def append( self, - moment_or_operation_tree: 'cirq.OP_TREE', - strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST, + moment_or_operation_tree: cirq.OP_TREE, + strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST, ) -> None: """Appends operations onto the end of the circuit. @@ -2454,9 +2453,7 @@ def append( """ self.insert(len(self._moments), moment_or_operation_tree, strategy) - def clear_operations_touching( - self, qubits: Iterable['cirq.Qid'], moment_indices: Iterable[int] - ): + def clear_operations_touching(self, qubits: Iterable[cirq.Qid], moment_indices: Iterable[int]): """Clears operations that are touching given qubits at given moments. Args: @@ -2471,10 +2468,10 @@ def clear_operations_touching( self._mutated() @property - def moments(self) -> Sequence['cirq.Moment']: + def moments(self) -> Sequence[cirq.Moment]: return self._moments - def with_noise(self, noise: 'cirq.NOISE_MODEL_LIKE') -> 'cirq.Circuit': + def with_noise(self, noise: cirq.NOISE_MODEL_LIKE) -> cirq.Circuit: """Make a noisy version of the circuit. Args: @@ -2496,10 +2493,10 @@ def with_noise(self, noise: 'cirq.NOISE_MODEL_LIKE') -> 'cirq.Circuit': def _pick_inserted_ops_moment_indices( - operations: Sequence['cirq.Operation'], + operations: Sequence[cirq.Operation], start: int = 0, - frontier: Optional[Dict['cirq.Qid', int]] = None, -) -> Tuple[Sequence[int], Dict['cirq.Qid', int]]: + frontier: Optional[Dict[cirq.Qid, int]] = None, +) -> Tuple[Sequence[int], Dict[cirq.Qid, int]]: """Greedily assigns operations to moments. Args: @@ -2525,7 +2522,7 @@ def _pick_inserted_ops_moment_indices( return moment_indices, frontier -def _get_moment_annotations(moment: 'cirq.Moment') -> Iterator['cirq.Operation']: +def _get_moment_annotations(moment: cirq.Moment) -> Iterator[cirq.Operation]: for op in moment.operations: if op.qubits: continue @@ -2541,14 +2538,14 @@ def _get_moment_annotations(moment: 'cirq.Moment') -> Iterator['cirq.Operation'] def _draw_moment_annotations( *, - moment: 'cirq.Moment', + moment: cirq.Moment, col: int, use_unicode_characters: bool, - label_map: Dict['cirq.LabelEntity', int], - out_diagram: 'cirq.TextDiagramDrawer', + label_map: Dict[cirq.LabelEntity, int], + out_diagram: cirq.TextDiagramDrawer, precision: Optional[int], get_circuit_diagram_info: Callable[ - ['cirq.Operation', 'cirq.CircuitDiagramInfoArgs'], 'cirq.CircuitDiagramInfo' + [cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo ], include_tags: bool, first_annotation_row: int, @@ -2573,14 +2570,14 @@ def _draw_moment_annotations( def _draw_moment_in_diagram( *, - moment: 'cirq.Moment', + moment: cirq.Moment, use_unicode_characters: bool, - label_map: Dict['cirq.LabelEntity', int], - out_diagram: 'cirq.TextDiagramDrawer', + label_map: Dict[cirq.LabelEntity, int], + out_diagram: cirq.TextDiagramDrawer, precision: Optional[int], moment_groups: List[Tuple[int, int]], get_circuit_diagram_info: Optional[ - Callable[['cirq.Operation', 'cirq.CircuitDiagramInfoArgs'], 'cirq.CircuitDiagramInfo'] + Callable[[cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo] ], include_tags: bool, first_annotation_row: int, @@ -2665,7 +2662,7 @@ def _draw_moment_in_diagram( moment_groups.append((x0, max_x)) -def _get_global_phase_and_tags_for_op(op: 'cirq.Operation') -> Tuple[Optional[complex], List[Any]]: +def _get_global_phase_and_tags_for_op(op: cirq.Operation) -> Tuple[Optional[complex], List[Any]]: if isinstance(op.gate, ops.GlobalPhaseGate): return complex(op.gate.coefficient), list(op.tags) elif isinstance(op.untagged, CircuitOperation): @@ -2699,7 +2696,7 @@ def _formatted_phase(coefficient: complex, unicode: bool, precision: Optional[in def _draw_moment_groups_in_diagram( moment_groups: List[Tuple[int, int]], use_unicode_characters: bool, - out_diagram: 'cirq.TextDiagramDrawer', + out_diagram: cirq.TextDiagramDrawer, ): out_diagram.insert_empty_rows(0) h = out_diagram.height() @@ -2729,9 +2726,9 @@ def _draw_moment_groups_in_diagram( def _apply_unitary_circuit( - circuit: 'cirq.AbstractCircuit', + circuit: cirq.AbstractCircuit, state: np.ndarray, - qubits: Tuple['cirq.Qid', ...], + qubits: Tuple[cirq.Qid, ...], dtype: Type[np.complexfloating], ) -> np.ndarray: """Applies a circuit's unitary effect to the given vector or matrix. @@ -2775,7 +2772,7 @@ def on_stuck(bad_op): return result -def _decompose_measurement_inversions(op: 'cirq.Operation') -> 'cirq.OP_TREE': +def _decompose_measurement_inversions(op: cirq.Operation) -> cirq.OP_TREE: if isinstance(op.gate, ops.MeasurementGate): return [ops.X(q) for q, b in zip(op.qubits, op.gate.invert_mask) if b] return NotImplemented @@ -2848,7 +2845,7 @@ def _group_into_moment_compatible(inputs: Sequence[_MOMENT_OR_OP]) -> Iterator[L [X(a), Moment(X(b)), X(c)] -> [[X(a)], [Moment(X(b))], [X(c)]] """ batch: List[_MOMENT_OR_OP] = [] - batch_qubits: Set['cirq.Qid'] = set() + batch_qubits: Set[cirq.Qid] = set() for mop in inputs: is_moment = isinstance(mop, cirq.Moment) if (is_moment and batch) or not batch_qubits.isdisjoint(mop.qubits): @@ -2866,9 +2863,9 @@ def _group_into_moment_compatible(inputs: Sequence[_MOMENT_OR_OP]) -> Iterator[L def get_earliest_accommodating_moment_index( moment_or_operation: _MOMENT_OR_OP, - qubit_indices: Dict['cirq.Qid', int], - mkey_indices: Dict['cirq.MeasurementKey', int], - ckey_indices: Dict['cirq.MeasurementKey', int], + qubit_indices: Dict[cirq.Qid, int], + mkey_indices: Dict[cirq.MeasurementKey, int], + ckey_indices: Dict[cirq.MeasurementKey, int], length: Optional[int] = None, ) -> int: """Get the index of the earliest moment that can accommodate the given moment or operation. @@ -2954,9 +2951,9 @@ class _PlacementCache: def __init__(self) -> None: # These are dicts from the qubit/key to the greatest moment index that has it. - self._qubit_indices: Dict['cirq.Qid', int] = {} - self._mkey_indices: Dict['cirq.MeasurementKey', int] = {} - self._ckey_indices: Dict['cirq.MeasurementKey', int] = {} + self._qubit_indices: Dict[cirq.Qid, int] = {} + self._mkey_indices: Dict[cirq.MeasurementKey, int] = {} + self._ckey_indices: Dict[cirq.MeasurementKey, int] = {} # For keeping track of length of the circuit thus far. self._length = 0 diff --git a/cirq-core/cirq/circuits/circuit_operation.py b/cirq-core/cirq/circuits/circuit_operation.py index a7cab197816..45e632407bb 100644 --- a/cirq-core/cirq/circuits/circuit_operation.py +++ b/cirq-core/cirq/circuits/circuit_operation.py @@ -18,6 +18,9 @@ applied as part of a larger circuit, a CircuitOperation will execute all component operations in order, including any nested CircuitOperations. """ + +from __future__ import annotations + import math from functools import cached_property from typing import ( @@ -81,16 +84,16 @@ class CircuitOperation(ops.Operation): def __init__( self, - circuit: 'cirq.FrozenCircuit', + circuit: cirq.FrozenCircuit, repetitions: INT_TYPE = 1, - qubit_map: Optional[Dict['cirq.Qid', 'cirq.Qid']] = None, + qubit_map: Optional[Dict[cirq.Qid, cirq.Qid]] = None, measurement_key_map: Optional[Dict[str, str]] = None, param_resolver: Optional[study.ParamResolverOrSimilarType] = None, repetition_ids: Optional[Sequence[str]] = None, parent_path: Tuple[str, ...] = (), - extern_keys: FrozenSet['cirq.MeasurementKey'] = frozenset(), + extern_keys: FrozenSet[cirq.MeasurementKey] = frozenset(), use_repetition_ids: Optional[bool] = None, - repeat_until: Optional['cirq.Condition'] = None, + repeat_until: Optional[cirq.Condition] = None, ): """Initializes a CircuitOperation. @@ -214,7 +217,7 @@ def __init__( raise ValueError('Infinite loop: condition is not modified in subcircuit.') @property - def circuit(self) -> 'cirq.FrozenCircuit': + def circuit(self) -> cirq.FrozenCircuit: return self._circuit @property @@ -230,11 +233,11 @@ def use_repetition_ids(self) -> bool: return self._use_repetition_ids @property - def repeat_until(self) -> Optional['cirq.Condition']: + def repeat_until(self) -> Optional[cirq.Condition]: return self._repeat_until @property - def qubit_map(self) -> Mapping['cirq.Qid', 'cirq.Qid']: + def qubit_map(self) -> Mapping[cirq.Qid, cirq.Qid]: return self._qubit_map @property @@ -249,14 +252,14 @@ def param_resolver(self) -> study.ParamResolver: def parent_path(self) -> Tuple[str, ...]: return self._parent_path - def base_operation(self) -> 'cirq.CircuitOperation': + def base_operation(self) -> cirq.CircuitOperation: """Returns a copy of this operation with only the wrapped circuit. Key and qubit mappings, parameter values, and repetitions are not copied. """ return CircuitOperation(self.circuit) - def replace(self, **changes) -> 'cirq.CircuitOperation': + def replace(self, **changes) -> cirq.CircuitOperation: """Returns a copy of this operation with the specified changes.""" kwargs = { 'circuit': self.circuit, @@ -293,7 +296,7 @@ def __eq__(self, other) -> bool: # Methods for getting post-mapping properties of the contained circuit. @property - def qubits(self) -> Tuple['cirq.Qid', ...]: + def qubits(self) -> Tuple[cirq.Qid, ...]: """Returns the qubits operated on by this object.""" ordered_qubits = ops.QubitOrder.DEFAULT.order_for(self.circuit.all_qubits()) return tuple(self.qubit_map.get(q, q) for q in ordered_qubits) @@ -319,7 +322,7 @@ def _ensure_deterministic_loop_count(self): raise ValueError('Cannot unroll circuit due to nondeterministic repetitions') @cached_property - def _measurement_key_objs(self) -> FrozenSet['cirq.MeasurementKey']: + def _measurement_key_objs(self) -> FrozenSet[cirq.MeasurementKey]: circuit_keys = protocols.measurement_key_objs(self.circuit) if circuit_keys and self.use_repetition_ids: self._ensure_deterministic_loop_count() @@ -337,14 +340,14 @@ def _measurement_key_objs(self) -> FrozenSet['cirq.MeasurementKey']: for key in circuit_keys ) - def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']: + def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]: return self._measurement_key_objs def _measurement_key_names_(self) -> FrozenSet[str]: return frozenset(str(key) for key in self._measurement_key_objs_()) @cached_property - def _control_keys(self) -> FrozenSet['cirq.MeasurementKey']: + def _control_keys(self) -> FrozenSet[cirq.MeasurementKey]: keys = ( frozenset() if not protocols.control_keys(self.circuit) @@ -355,7 +358,7 @@ def _control_keys(self) -> FrozenSet['cirq.MeasurementKey']: keys |= frozenset(mapped_repeat_until.keys) - self._measurement_key_objs_() return keys - def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']: + def _control_keys_(self) -> FrozenSet[cirq.MeasurementKey]: return self._control_keys def _is_parameterized_(self) -> bool: @@ -370,7 +373,7 @@ def _parameter_names_generator(self) -> Iterator[str]: yield from protocols.parameter_names(self._mapped_any_loop) @cached_property - def _mapped_any_loop(self) -> 'cirq.Circuit': + def _mapped_any_loop(self) -> cirq.Circuit: circuit = self.circuit.unfreeze() if self.qubit_map: circuit = circuit.transform_qubits(lambda q: self.qubit_map.get(q, q)) @@ -382,7 +385,7 @@ def _mapped_any_loop(self) -> 'cirq.Circuit': circuit = protocols.resolve_parameters(circuit, self.param_resolver, recursive=False) return circuit.unfreeze(copy=False) - def _mapped_single_loop(self, repetition_id: Optional[str] = None) -> 'cirq.Circuit': + def _mapped_single_loop(self, repetition_id: Optional[str] = None) -> cirq.Circuit: circuit = self._mapped_any_loop if repetition_id: circuit = protocols.with_rescoped_keys(circuit, (repetition_id,)) @@ -391,7 +394,7 @@ def _mapped_single_loop(self, repetition_id: Optional[str] = None) -> 'cirq.Circ ) @cached_property - def _mapped_repeat_until(self) -> Optional['cirq.Condition']: + def _mapped_repeat_until(self) -> Optional[cirq.Condition]: """Applies measurement_key_map, param_resolver, and current scope to repeat_until.""" repeat_until = self.repeat_until if not repeat_until: @@ -410,7 +413,7 @@ def _mapped_repeat_until(self) -> Optional['cirq.Condition']: bindable_keys=self._extern_keys | self._measurement_key_objs, ) - def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit': + def mapped_circuit(self, deep: bool = False) -> cirq.Circuit: """Applies all maps to the contained circuit and returns the result. Args: @@ -438,14 +441,14 @@ def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit': ) return circuit - def mapped_op(self, deep: bool = False) -> 'cirq.CircuitOperation': + def mapped_op(self, deep: bool = False) -> cirq.CircuitOperation: """As `mapped_circuit`, but wraps the result in a CircuitOperation.""" return CircuitOperation(circuit=self.mapped_circuit(deep=deep).freeze()) - def _decompose_(self) -> Iterator['cirq.Operation']: + def _decompose_(self) -> Iterator[cirq.Operation]: return self.mapped_circuit(deep=False).all_operations() - def _act_on_(self, sim_state: 'cirq.SimulationStateBase') -> bool: + def _act_on_(self, sim_state: cirq.SimulationStateBase) -> bool: mapped_repeat_until = self._mapped_repeat_until if mapped_repeat_until: circuit = self._mapped_single_loop() @@ -593,7 +596,7 @@ def repeat( repetitions: Optional[IntParam] = None, repetition_ids: Optional[Sequence[str]] = None, use_repetition_ids: Optional[bool] = None, - ) -> 'CircuitOperation': + ) -> CircuitOperation: """Returns a copy of this operation repeated 'repetitions' times. Each repetition instance will be identified by a single repetition_id. @@ -656,7 +659,7 @@ def repeat( use_repetition_ids=use_repetition_ids, ) - def __pow__(self, power: IntParam) -> 'cirq.CircuitOperation': + def __pow__(self, power: IntParam) -> cirq.CircuitOperation: return self.repeat(power) def _with_key_path_(self, path: Tuple[str, ...]): @@ -666,7 +669,7 @@ def _with_key_path_prefix_(self, prefix: Tuple[str, ...]): return self.replace(parent_path=prefix + self.parent_path) def _with_rescoped_keys_( - self, path: Tuple[str, ...], bindable_keys: FrozenSet['cirq.MeasurementKey'] + self, path: Tuple[str, ...], bindable_keys: FrozenSet[cirq.MeasurementKey] ): # The following line prevents binding to measurement keys in previous repeated subcircuits # "just because their repetition ids matched". If we eventually decide to change that @@ -690,7 +693,7 @@ def with_key_path(self, path: Tuple[str, ...]): """ return self._with_key_path_(path) - def with_repetition_ids(self, repetition_ids: List[str]) -> 'cirq.CircuitOperation': + def with_repetition_ids(self, repetition_ids: List[str]) -> cirq.CircuitOperation: """Returns a copy of this `CircuitOperation` with the given repetition IDs. Args: @@ -703,8 +706,8 @@ def with_repetition_ids(self, repetition_ids: List[str]) -> 'cirq.CircuitOperati return self.replace(repetition_ids=repetition_ids) def with_qubit_mapping( - self, qubit_map: Union[Mapping['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']] - ) -> 'cirq.CircuitOperation': + self, qubit_map: Union[Mapping[cirq.Qid, cirq.Qid], Callable[[cirq.Qid], cirq.Qid]] + ) -> cirq.CircuitOperation: """Returns a copy of this operation with an updated qubit mapping. Users should pass either 'qubit_map' or 'transform' to this method. @@ -743,7 +746,7 @@ def with_qubit_mapping( ) return new_op - def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'cirq.CircuitOperation': + def with_qubits(self, *new_qubits: cirq.Qid) -> cirq.CircuitOperation: """Returns a copy of this operation with an updated qubit mapping. Args: @@ -763,7 +766,7 @@ def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'cirq.CircuitOperation': raise ValueError(f'Expected {expected} qubits, got {len(new_qubits)}.') return self.with_qubit_mapping(dict(zip(self.qubits, new_qubits))) - def with_measurement_key_mapping(self, key_map: Mapping[str, str]) -> 'cirq.CircuitOperation': + def with_measurement_key_mapping(self, key_map: Mapping[str, str]) -> cirq.CircuitOperation: """Returns a copy of this operation with an updated key mapping. Args: @@ -797,12 +800,12 @@ def with_measurement_key_mapping(self, key_map: Mapping[str, str]) -> 'cirq.Circ ) return new_op - def _with_measurement_key_mapping_(self, key_map: Mapping[str, str]) -> 'cirq.CircuitOperation': + def _with_measurement_key_mapping_(self, key_map: Mapping[str, str]) -> cirq.CircuitOperation: return self.with_measurement_key_mapping(key_map) def with_params( - self, param_values: 'cirq.ParamResolverOrSimilarType', recursive: bool = False - ) -> 'cirq.CircuitOperation': + self, param_values: cirq.ParamResolverOrSimilarType, recursive: bool = False + ) -> cirq.CircuitOperation: """Returns a copy of this operation with an updated ParamResolver. Any existing parameter mappings will have their values updated given @@ -838,8 +841,8 @@ def with_params( return self.replace(param_resolver=new_params) def _resolve_parameters_( - self, resolver: 'cirq.ParamResolver', recursive: bool - ) -> 'cirq.CircuitOperation': + self, resolver: cirq.ParamResolver, recursive: bool + ) -> cirq.CircuitOperation: resolved = self.with_params(resolver.param_dict, recursive) # repetitions can resolve to a float, but this is ok since constructor converts to # nearby int. diff --git a/cirq-core/cirq/circuits/circuit_operation_test.py b/cirq-core/cirq/circuits/circuit_operation_test.py index f9b27e5a56a..b42a6aaa39e 100644 --- a/cirq-core/cirq/circuits/circuit_operation_test.py +++ b/cirq-core/cirq/circuits/circuit_operation_test.py @@ -168,7 +168,7 @@ def test_with_qubits(): assert op_base.with_qubit_mapping({a: d, b: c, d: a}) == op_with_qubits - def map_fn(qubit: 'cirq.Qid') -> 'cirq.Qid': + def map_fn(qubit: cirq.Qid) -> cirq.Qid: if qubit == a: return d if qubit == b: diff --git a/cirq-core/cirq/circuits/circuit_test.py b/cirq-core/cirq/circuits/circuit_test.py index 073429fa83b..79fcf0fa410 100644 --- a/cirq-core/cirq/circuits/circuit_test.py +++ b/cirq-core/cirq/circuits/circuit_test.py @@ -11,12 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + import itertools import os import time from collections import defaultdict from random import randint, random, randrange, sample -from typing import Iterator, Optional, Tuple, TYPE_CHECKING +from typing import Iterator, Optional, Tuple import numpy as np import pytest @@ -49,9 +50,6 @@ class _Foxy(ValidatingTestDevice): ) -if TYPE_CHECKING: - import cirq - q0, q1, q2, q3 = cirq.LineQubit.range(4) @@ -893,8 +891,8 @@ def __init__(self, replacer=(lambda x: x)): self.replacer = replacer def optimization_at( - self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation' - ) -> Optional['cirq.PointOptimizationSummary']: + self, circuit: cirq.Circuit, index: int, op: cirq.Operation + ) -> Optional[cirq.PointOptimizationSummary]: new_ops = self.replacer(op) return cirq.PointOptimizationSummary( clear_span=1, clear_qubits=op.qubits, new_operations=new_ops diff --git a/cirq-core/cirq/circuits/frozen_circuit.py b/cirq-core/cirq/circuits/frozen_circuit.py index 1a9587ed38c..fa63c50e187 100644 --- a/cirq-core/cirq/circuits/frozen_circuit.py +++ b/cirq-core/cirq/circuits/frozen_circuit.py @@ -11,7 +11,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + """An immutable version of the Circuit data structure.""" + +from __future__ import annotations + from functools import cached_property from types import NotImplementedType from typing import ( @@ -46,8 +50,8 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey): def __init__( self, - *contents: 'cirq.OP_TREE', - strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST, + *contents: cirq.OP_TREE, + strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST, tags: Sequence[Hashable] = (), ) -> None: """Initializes a frozen circuit. @@ -71,19 +75,19 @@ def __init__( self._tags = tuple(tags) @classmethod - def _from_moments(cls, moments: Iterable['cirq.Moment']) -> 'FrozenCircuit': + def _from_moments(cls, moments: Iterable[cirq.Moment]) -> FrozenCircuit: new_circuit = FrozenCircuit() new_circuit._moments = tuple(moments) return new_circuit @property - def moments(self) -> Sequence['cirq.Moment']: + def moments(self) -> Sequence[cirq.Moment]: return self._moments - def freeze(self) -> 'cirq.FrozenCircuit': + def freeze(self) -> cirq.FrozenCircuit: return self - def unfreeze(self, copy: bool = True) -> 'cirq.Circuit': + def unfreeze(self, copy: bool = True) -> cirq.Circuit: return Circuit._from_moments(self._moments) @property @@ -92,11 +96,11 @@ def tags(self) -> Tuple[Hashable, ...]: return self._tags @cached_property - def untagged(self) -> 'cirq.FrozenCircuit': + def untagged(self) -> cirq.FrozenCircuit: """Returns the underlying FrozenCircuit without any tags.""" return self._from_moments(self._moments) if self.tags else self - def with_tags(self, *new_tags: Hashable) -> 'cirq.FrozenCircuit': + def with_tags(self, *new_tags: Hashable) -> cirq.FrozenCircuit: """Creates a new tagged `FrozenCircuit` with `self.tags` and `new_tags` combined.""" if not new_tags: return self @@ -146,28 +150,28 @@ def _is_measurement_(self) -> bool: return protocols.is_measurement(self.unfreeze()) @_compat.cached_method - def all_qubits(self) -> FrozenSet['cirq.Qid']: + def all_qubits(self) -> FrozenSet[cirq.Qid]: return super().all_qubits() @cached_property - def _all_operations(self) -> Tuple['cirq.Operation', ...]: + def _all_operations(self) -> Tuple[cirq.Operation, ...]: return tuple(super().all_operations()) - def all_operations(self) -> Iterator['cirq.Operation']: + def all_operations(self) -> Iterator[cirq.Operation]: return iter(self._all_operations) def has_measurements(self) -> bool: return self._is_measurement_() @_compat.cached_method - def all_measurement_key_objs(self) -> FrozenSet['cirq.MeasurementKey']: + def all_measurement_key_objs(self) -> FrozenSet[cirq.MeasurementKey]: return super().all_measurement_key_objs() - def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']: + def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]: return self.all_measurement_key_objs() @_compat.cached_method - def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']: + def _control_keys_(self) -> FrozenSet[cirq.MeasurementKey]: return super()._control_keys_() @_compat.cached_method @@ -190,8 +194,8 @@ def _parameter_names_(self) -> AbstractSet[str]: return super()._parameter_names_() | tag_params def _resolve_parameters_( - self, resolver: 'cirq.ParamResolver', recursive: bool - ) -> 'cirq.FrozenCircuit': + self, resolver: cirq.ParamResolver, recursive: bool + ) -> cirq.FrozenCircuit: resolved_circuit = super()._resolve_parameters_(resolver, recursive) resolved_tags = [ protocols.resolve_parameters(tag, resolver, recursive) for tag in self.tags @@ -201,23 +205,23 @@ def _resolve_parameters_( def _measurement_key_names_(self) -> FrozenSet[str]: return self.all_measurement_key_names() - def __add__(self, other) -> 'cirq.FrozenCircuit': + def __add__(self, other) -> cirq.FrozenCircuit: return (self.unfreeze() + other).freeze() - def __radd__(self, other) -> 'cirq.FrozenCircuit': + def __radd__(self, other) -> cirq.FrozenCircuit: return (other + self.unfreeze()).freeze() # Needed for numpy to handle multiplication by np.int64 correctly. __array_priority__ = 10000 # TODO: handle multiplication / powers differently? - def __mul__(self, other) -> 'cirq.FrozenCircuit': + def __mul__(self, other) -> cirq.FrozenCircuit: return (self.unfreeze() * other).freeze() - def __rmul__(self, other) -> 'cirq.FrozenCircuit': + def __rmul__(self, other) -> cirq.FrozenCircuit: return (other * self.unfreeze()).freeze() - def __pow__(self, other) -> 'cirq.FrozenCircuit': + def __pow__(self, other) -> cirq.FrozenCircuit: try: return (self.unfreeze() ** other).freeze() except: @@ -238,20 +242,20 @@ def _from_json_dict_(cls, moments, *, tags=(), **kwargs): return cls(moments, strategy=InsertStrategy.EARLIEST, tags=tags) def concat_ragged( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.FrozenCircuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.FrozenCircuit: return AbstractCircuit.concat_ragged(*circuits, align=align).freeze() concat_ragged.__doc__ = AbstractCircuit.concat_ragged.__doc__ def zip( - *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT - ) -> 'cirq.FrozenCircuit': + *circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT + ) -> cirq.FrozenCircuit: return AbstractCircuit.zip(*circuits, align=align).freeze() zip.__doc__ = AbstractCircuit.zip.__doc__ - def to_op(self) -> 'cirq.CircuitOperation': + def to_op(self) -> cirq.CircuitOperation: """Creates a CircuitOperation wrapping this circuit.""" from cirq.circuits import CircuitOperation diff --git a/cirq-core/cirq/circuits/moment.py b/cirq-core/cirq/circuits/moment.py index 1aa2b555584..3cf64ae268c 100644 --- a/cirq-core/cirq/circuits/moment.py +++ b/cirq-core/cirq/circuits/moment.py @@ -14,6 +14,8 @@ """A simplified time-slice of operations within a sequenced circuit.""" +from __future__ import annotations + import itertools from functools import cached_property from types import NotImplementedType @@ -55,7 +57,7 @@ ) -def _default_breakdown(qid: 'cirq.Qid') -> Tuple[Any, Any]: +def _default_breakdown(qid: cirq.Qid) -> Tuple[Any, Any]: # Attempt to convert into a position on the complex plane. try: plane_pos = complex(qid) # type: ignore @@ -82,7 +84,7 @@ class Moment: are no such operations, returns an empty Moment. """ - def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) -> None: + def __init__(self, *contents: cirq.OP_TREE, _flatten_contents: bool = True) -> None: """Constructs a moment with the given operations. Args: @@ -102,10 +104,10 @@ def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) -> if _flatten_contents else cast(Tuple['cirq.Operation'], contents) ) - self._sorted_operations: Optional[Tuple['cirq.Operation', ...]] = None + self._sorted_operations: Optional[Tuple[cirq.Operation, ...]] = None # An internal dictionary to support efficient operation access by qubit. - self._qubit_to_op: Dict['cirq.Qid', 'cirq.Operation'] = {} + self._qubit_to_op: Dict[cirq.Qid, cirq.Operation] = {} for op in self.operations: for q in op.qubits: # Check that operations don't overlap. @@ -113,11 +115,11 @@ def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) -> raise ValueError(f'Overlapping operations: {self.operations}') self._qubit_to_op[q] = op - self._measurement_key_objs: Optional[FrozenSet['cirq.MeasurementKey']] = None - self._control_keys: Optional[FrozenSet['cirq.MeasurementKey']] = None + self._measurement_key_objs: Optional[FrozenSet[cirq.MeasurementKey]] = None + self._control_keys: Optional[FrozenSet[cirq.MeasurementKey]] = None @classmethod - def from_ops(cls, *ops: 'cirq.Operation') -> 'cirq.Moment': + def from_ops(cls, *ops: cirq.Operation) -> cirq.Moment: """Construct a Moment from the given operations. This avoids calling `flatten_to_ops` in the moment constructor, which @@ -131,14 +133,14 @@ def from_ops(cls, *ops: 'cirq.Operation') -> 'cirq.Moment': return cls(*ops, _flatten_contents=False) @property - def operations(self) -> Tuple['cirq.Operation', ...]: + def operations(self) -> Tuple[cirq.Operation, ...]: return self._operations @cached_property - def qubits(self) -> FrozenSet['cirq.Qid']: + def qubits(self) -> FrozenSet[cirq.Qid]: return frozenset(self._qubit_to_op) - def operates_on_single_qubit(self, qubit: 'cirq.Qid') -> bool: + def operates_on_single_qubit(self, qubit: cirq.Qid) -> bool: """Determines if the moment has operations touching the given qubit. Args: qubit: The qubit that may or may not be touched by operations. @@ -147,7 +149,7 @@ def operates_on_single_qubit(self, qubit: 'cirq.Qid') -> bool: """ return qubit in self._qubit_to_op - def operates_on(self, qubits: Iterable['cirq.Qid']) -> bool: + def operates_on(self, qubits: Iterable[cirq.Qid]) -> bool: """Determines if the moment has operations touching the given qubits. Args: @@ -158,7 +160,7 @@ def operates_on(self, qubits: Iterable['cirq.Qid']) -> bool: """ return not self._qubit_to_op.keys().isdisjoint(qubits) - def operation_at(self, qubit: raw_types.Qid) -> Optional['cirq.Operation']: + def operation_at(self, qubit: raw_types.Qid) -> Optional[cirq.Operation]: """Returns the operation on a certain qubit for the moment. Args: @@ -172,7 +174,7 @@ def operation_at(self, qubit: raw_types.Qid) -> Optional['cirq.Operation']: return self.__getitem__(qubit) return None - def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment': + def with_operation(self, operation: cirq.Operation) -> cirq.Moment: """Returns an equal moment, but with the given op added. Args: @@ -200,7 +202,7 @@ def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment': return m - def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment': + def with_operations(self, *contents: cirq.OP_TREE) -> cirq.Moment: """Returns a new moment with the given contents added. Args: @@ -237,7 +239,7 @@ def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment': return m - def without_operations_touching(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment': + def without_operations_touching(self, qubits: Iterable[cirq.Qid]) -> cirq.Moment: """Returns an equal moment, but without ops on the given qubits. Args: @@ -263,11 +265,9 @@ def _is_parameterized_(self) -> bool: def _parameter_names_(self) -> AbstractSet[str]: return {name for op in self for name in protocols.parameter_names(op)} - def _resolve_parameters_( - self, resolver: 'cirq.ParamResolver', recursive: bool - ) -> 'cirq.Moment': + def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> cirq.Moment: changed = False - resolved_ops: List['cirq.Operation'] = [] + resolved_ops: List[cirq.Operation] = [] for op in self: resolved_op = protocols.resolve_parameters(op, resolver, recursive) changed = ( @@ -294,21 +294,21 @@ def _with_measurement_key_mapping_(self, key_map: Mapping[str, str]): def _measurement_key_names_(self) -> FrozenSet[str]: return frozenset(str(key) for key in self._measurement_key_objs_()) - def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']: + def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]: if self._measurement_key_objs is None: self._measurement_key_objs = frozenset( key for op in self.operations for key in protocols.measurement_key_objs(op) ) return self._measurement_key_objs - def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']: + 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 _sorted_operations_(self) -> Tuple['cirq.Operation', ...]: + def _sorted_operations_(self) -> Tuple[cirq.Operation, ...]: if self._sorted_operations is None: self._sorted_operations = tuple(sorted(self._operations, key=lambda op: op.qubits)) return self._sorted_operations @@ -330,7 +330,7 @@ def _with_key_path_prefix_(self, prefix: Tuple[str, ...]): ) def _with_rescoped_keys_( - self, path: Tuple[str, ...], bindable_keys: FrozenSet['cirq.MeasurementKey'] + self, path: Tuple[str, ...], bindable_keys: FrozenSet[cirq.MeasurementKey] ): return Moment( protocols.with_rescoped_keys(op, path, bindable_keys) for op in self.operations @@ -373,7 +373,7 @@ def __getstate__(self) -> Dict[str, Any]: del state[hash_attr] return state - def __iter__(self) -> Iterator['cirq.Operation']: + def __iter__(self) -> Iterator[cirq.Operation]: return iter(self.operations) def __pow__(self, power): @@ -402,12 +402,12 @@ def __repr__(self) -> str: def __str__(self) -> str: return self.to_text_diagram() - def _decompose_(self) -> 'cirq.OP_TREE': + def _decompose_(self) -> cirq.OP_TREE: """See `cirq.SupportsDecompose`.""" return self._operations def transform_qubits( - self, qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']] + self, qubit_map: Union[Dict[cirq.Qid, cirq.Qid], Callable[[cirq.Qid], cirq.Qid]] ) -> Self: """Returns the same moment, but with different qubits. @@ -421,7 +421,7 @@ def transform_qubits( """ return self.__class__(op.transform_qubits(qubit_map) for op in self.operations) - def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment': + def expand_to(self, qubits: Iterable[cirq.Qid]) -> cirq.Moment: """Returns self expanded to given superset of qubits by making identities explicit. Args: @@ -480,13 +480,13 @@ def _kraus_(self) -> Sequence[np.ndarray]: qubit_to_row_subscript = dict(zip(qubits, 'abcdefghij')) qubit_to_col_subscript = dict(zip(qubits, 'ABCDEFGHIJ')) - def row_subscripts(qs: Sequence['cirq.Qid']) -> str: + def row_subscripts(qs: Sequence[cirq.Qid]) -> str: return ''.join(qubit_to_row_subscript[q] for q in qs) - def col_subscripts(qs: Sequence['cirq.Qid']) -> str: + def col_subscripts(qs: Sequence[cirq.Qid]) -> str: return ''.join(qubit_to_col_subscript[q] for q in qs) - def kraus_tensors(op: 'cirq.Operation') -> Sequence[np.ndarray]: + def kraus_tensors(op: cirq.Operation) -> Sequence[np.ndarray]: return tuple(np.reshape(k, (2, 2) * len(op.qubits)) for k in protocols.kraus(op)) input_subscripts = ','.join( @@ -523,12 +523,12 @@ def _json_dict_(self) -> Dict[str, Any]: def _from_json_dict_(cls, operations, **kwargs): return cls.from_ops(*operations) - def __add__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment': + def __add__(self, other: cirq.OP_TREE) -> cirq.Moment: if isinstance(other, circuit.AbstractCircuit): return NotImplemented # Delegate to Circuit.__radd__. return self.with_operations(other) - def __sub__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment': + def __sub__(self, other: cirq.OP_TREE) -> cirq.Moment: must_remove = set(op_tree.flatten_to_ops(other)) new_ops = [] for op in self.operations: @@ -546,11 +546,11 @@ def __sub__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment': # pylint: disable=function-redefined @overload - def __getitem__(self, key: raw_types.Qid) -> 'cirq.Operation': + def __getitem__(self, key: raw_types.Qid) -> cirq.Operation: pass @overload - def __getitem__(self, key: Iterable[raw_types.Qid]) -> 'cirq.Moment': + def __getitem__(self, key: Iterable[raw_types.Qid]) -> cirq.Moment: pass def __getitem__(self, key): @@ -567,10 +567,10 @@ def __getitem__(self, key): return Moment(frozenset(ops_to_keep)) def to_text_diagram( - self: 'cirq.Moment', + self: cirq.Moment, *, - xy_breakdown_func: Callable[['cirq.Qid'], Tuple[Any, Any]] = _default_breakdown, - extra_qubits: Iterable['cirq.Qid'] = (), + xy_breakdown_func: Callable[[cirq.Qid], Tuple[Any, Any]] = _default_breakdown, + extra_qubits: Iterable[cirq.Qid] = (), use_unicode_characters: bool = True, precision: Optional[int] = None, include_tags: bool = True, diff --git a/cirq-core/cirq/circuits/optimization_pass.py b/cirq-core/cirq/circuits/optimization_pass.py index 6ab4d2543a8..8c892663409 100644 --- a/cirq-core/cirq/circuits/optimization_pass.py +++ b/cirq-core/cirq/circuits/optimization_pass.py @@ -13,6 +13,9 @@ # limitations under the License. """Defines the OptimizationPass type.""" + +from __future__ import annotations + import abc from collections import defaultdict from typing import Callable, cast, Dict, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING @@ -21,7 +24,6 @@ if TYPE_CHECKING: import cirq - from cirq.ops import Qid class PointOptimizationSummary: @@ -30,8 +32,8 @@ class PointOptimizationSummary: def __init__( self, clear_span: int, - clear_qubits: Iterable['cirq.Qid'], - new_operations: 'cirq.OP_TREE', + clear_qubits: Iterable[cirq.Qid], + new_operations: cirq.OP_TREE, preserve_moments: bool = False, ) -> None: """Inits PointOptimizationSummary. @@ -87,9 +89,7 @@ class PointOptimizer: def __init__( self, - post_clean_up: Callable[ - [Sequence['cirq.Operation']], 'cirq.OP_TREE' - ] = lambda op_list: op_list, + post_clean_up: Callable[[Sequence[cirq.Operation]], cirq.OP_TREE] = lambda op_list: op_list, ) -> None: """Inits PointOptimizer. @@ -100,13 +100,13 @@ def __init__( """ self.post_clean_up = post_clean_up - def __call__(self, circuit: 'cirq.Circuit'): + def __call__(self, circuit: cirq.Circuit): return self.optimize_circuit(circuit) @abc.abstractmethod def optimization_at( - self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation' - ) -> Optional['cirq.PointOptimizationSummary']: + self, circuit: cirq.Circuit, index: int, op: cirq.Operation + ) -> Optional[cirq.PointOptimizationSummary]: """Describes how to change operations near the given location. For example, this method could realize that the given operation is an @@ -126,8 +126,8 @@ def optimization_at( change should be made. """ - def optimize_circuit(self, circuit: 'cirq.Circuit'): - frontier: Dict['Qid', int] = defaultdict(lambda: 0) + def optimize_circuit(self, circuit: cirq.Circuit): + frontier: Dict[cirq.Qid, int] = defaultdict(lambda: 0) i = 0 while i < len(circuit): # Note: circuit may mutate as we go. for op in circuit[i].operations: diff --git a/cirq-core/cirq/circuits/optimization_pass_test.py b/cirq-core/cirq/circuits/optimization_pass_test.py index 2d94e837021..75f0e764c7e 100644 --- a/cirq-core/cirq/circuits/optimization_pass_test.py +++ b/cirq-core/cirq/circuits/optimization_pass_test.py @@ -11,7 +11,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import List, Optional, Set, TYPE_CHECKING + +from typing import List, Optional, Set import pytest @@ -19,9 +20,6 @@ from cirq import Operation, PointOptimizationSummary, PointOptimizer from cirq.testing import EqualsTester -if TYPE_CHECKING: - import cirq - def test_equality(): a = cirq.NamedQubit('a') @@ -63,8 +61,8 @@ class ReplaceWithXGates(PointOptimizer): """ def optimization_at( - self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation' - ) -> Optional['cirq.PointOptimizationSummary']: + self, circuit: cirq.Circuit, index: int, op: cirq.Operation + ) -> Optional[cirq.PointOptimizationSummary]: end = index + 1 new_ops = [cirq.X(q) for q in op.qubits] done = False @@ -157,8 +155,8 @@ class EverythingIs42(cirq.PointOptimizer): """Changes all single qubit operations to act on LineQubit(42)""" def optimization_at( - self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation' - ) -> Optional['cirq.PointOptimizationSummary']: + self, circuit: cirq.Circuit, index: int, op: cirq.Operation + ) -> Optional[cirq.PointOptimizationSummary]: new_op = op if len(op.qubits) == 1 and isinstance(op, cirq.GateOperation): new_op = op.gate(cirq.LineQubit(42)) diff --git a/cirq-core/cirq/circuits/qasm_output.py b/cirq-core/cirq/circuits/qasm_output.py index 887aa8ceae8..323100a6239 100644 --- a/cirq-core/cirq/circuits/qasm_output.py +++ b/cirq-core/cirq/circuits/qasm_output.py @@ -14,6 +14,8 @@ """Utility classes for representing QASM.""" +from __future__ import annotations + import re from typing import Callable, Dict, Iterator, Optional, Sequence, Tuple, TYPE_CHECKING, Union @@ -46,14 +48,14 @@ def _num_qubits_(self) -> int: return 1 @staticmethod - def from_matrix(mat: np.ndarray) -> 'QasmUGate': + def from_matrix(mat: np.ndarray) -> QasmUGate: pre_phase, rotation, post_phase = linalg.deconstruct_single_qubit_matrix_into_angles(mat) return QasmUGate(rotation / np.pi, post_phase / np.pi, pre_phase / np.pi) def _has_unitary_(self): return True - def _qasm_(self, qubits: Tuple['cirq.Qid', ...], args: 'cirq.QasmArgs') -> str: + def _qasm_(self, qubits: Tuple[cirq.Qid, ...], args: cirq.QasmArgs) -> str: args.validate_version('2.0', '3.0') return args.format( 'u3({0:half_turns},{1:half_turns},{2:half_turns}) {3};\n', @@ -86,13 +88,13 @@ def _json_dict_(self) -> Dict[str, float]: return {'theta': self.theta, 'phi': self.phi, 'lmda': self.lmda} @classmethod - def _from_json_dict_(cls, theta: float, phi: float, lmda: float, **kwargs) -> 'QasmUGate': + def _from_json_dict_(cls, theta: float, phi: float, lmda: float, **kwargs) -> QasmUGate: return cls(theta, phi, lmda) @value.value_equality class QasmTwoQubitGate(ops.Gate): - def __init__(self, kak: 'cirq.KakDecomposition') -> None: + def __init__(self, kak: cirq.KakDecomposition) -> None: """A two qubit gate represented in QASM by the KAK decomposition. All angles are in half turns. Assumes a canonicalized KAK @@ -110,7 +112,7 @@ def _value_equality_values_(self): return self.kak @staticmethod - def from_matrix(mat: np.ndarray, atol=1e-8) -> 'QasmTwoQubitGate': + def from_matrix(mat: np.ndarray, atol=1e-8) -> QasmTwoQubitGate: """Creates a QasmTwoQubitGate from the given matrix. Args: @@ -126,7 +128,7 @@ def from_matrix(mat: np.ndarray, atol=1e-8) -> 'QasmTwoQubitGate': def _unitary_(self): return protocols.unitary(self.kak) - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: q0, q1 = qubits x, y, z = self.kak.interaction_coefficients a = x * -2 / np.pi + 0.5 @@ -170,8 +172,8 @@ class QasmOutput: def __init__( self, - operations: 'cirq.OP_TREE', - qubits: Tuple['cirq.Qid', ...], + operations: cirq.OP_TREE, + qubits: Tuple[cirq.Qid, ...], header: str = '', precision: int = 10, version: str = '2.0', @@ -225,7 +227,7 @@ def _generate_measurement_ids(self) -> Tuple[Dict[str, str], Dict[str, Optional[ meas_key_id_map[key] = meas_id return meas_key_id_map, meas_comments - def _generate_qubit_ids(self) -> Dict['cirq.Qid', str]: + def _generate_qubit_ids(self) -> Dict[cirq.Qid, str]: return {qubit: f'q[{i}]' for i, qubit in enumerate(self.qubits)} def _generate_cregs(self, meas_key_id_map: Dict[str, str]) -> Dict[str, tuple[int, str]]: @@ -333,11 +335,11 @@ def output(text): def _write_operations( self, - op_tree: 'cirq.OP_TREE', + op_tree: cirq.OP_TREE, output: Callable[[str], None], output_line_gap: Callable[[int], None], ) -> None: - def keep(op: 'cirq.Operation') -> bool: + def keep(op: cirq.Operation) -> bool: return protocols.qasm(op, args=self.args, default=None) is not None def fallback(op): diff --git a/cirq-core/cirq/circuits/text_diagram_drawer.py b/cirq-core/cirq/circuits/text_diagram_drawer.py index fb3e74a0700..76ecdf1ed9b 100644 --- a/cirq-core/cirq/circuits/text_diagram_drawer.py +++ b/cirq-core/cirq/circuits/text_diagram_drawer.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import ( Any, Callable, @@ -171,7 +173,7 @@ def horizontal_line( x1, x2 = sorted([x1, x2]) self.horizontal_lines.append(_HorizontalLine(y, x1, x2, emphasize, doubled)) - def transpose(self) -> 'cirq.TextDiagramDrawer': + def transpose(self) -> cirq.TextDiagramDrawer: """Returns the same diagram, but mirrored across its diagonal.""" out = TextDiagramDrawer() out.entries = { @@ -333,14 +335,14 @@ def copy(self): horizontal_padding=self.horizontal_padding, ) - def shift(self, dx: int = 0, dy: int = 0) -> 'cirq.TextDiagramDrawer': + def shift(self, dx: int = 0, dy: int = 0) -> cirq.TextDiagramDrawer: self._transform_coordinates(lambda x, y: (x + dx, y + dy)) return self - def shifted(self, dx: int = 0, dy: int = 0) -> 'cirq.TextDiagramDrawer': + def shifted(self, dx: int = 0, dy: int = 0) -> cirq.TextDiagramDrawer: return self.copy().shift(dx, dy) - def superimpose(self, other: 'cirq.TextDiagramDrawer') -> 'cirq.TextDiagramDrawer': + def superimpose(self, other: cirq.TextDiagramDrawer) -> cirq.TextDiagramDrawer: self.entries.update(other.entries) self.horizontal_lines += other.horizontal_lines self.vertical_lines += other.vertical_lines @@ -348,13 +350,13 @@ def superimpose(self, other: 'cirq.TextDiagramDrawer') -> 'cirq.TextDiagramDrawe self.vertical_padding.update(other.vertical_padding) return self - def superimposed(self, other: 'cirq.TextDiagramDrawer') -> 'cirq.TextDiagramDrawer': + def superimposed(self, other: cirq.TextDiagramDrawer) -> cirq.TextDiagramDrawer: return self.copy().superimpose(other) @classmethod def vstack( cls, - diagrams: Sequence['cirq.TextDiagramDrawer'], + diagrams: Sequence[cirq.TextDiagramDrawer], padding_resolver: Optional[Callable[[Sequence[Optional[int]]], int]] = None, ): """Vertically stack text diagrams. @@ -395,7 +397,7 @@ def vstack( @classmethod def hstack( cls, - diagrams: Sequence['cirq.TextDiagramDrawer'], + diagrams: Sequence[cirq.TextDiagramDrawer], padding_resolver: Optional[Callable[[Sequence[Optional[int]]], int]] = None, ): """Horizontally stack text diagrams. diff --git a/cirq-core/cirq/contrib/acquaintance/bipartite.py b/cirq-core/cirq/contrib/acquaintance/bipartite.py index daeda827819..6e6916a7fad 100644 --- a/cirq-core/cirq/contrib/acquaintance/bipartite.py +++ b/cirq-core/cirq/contrib/acquaintance/bipartite.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import enum import itertools from typing import Dict, Iterator, Sequence, Tuple, TYPE_CHECKING, Union @@ -62,7 +64,7 @@ def __init__( self, subgraph: Union[str, BipartiteGraphType], part_size: int, - swap_gate: 'cirq.Gate' = ops.SWAP, + swap_gate: cirq.Gate = ops.SWAP, ) -> None: super().__init__(2 * part_size, swap_gate) self.part_size = part_size @@ -71,7 +73,7 @@ def __init__( ) self.swap_gate = swap_gate - def decompose_complete(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def decompose_complete(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: swap_gate = SwapPermutationGate(self.swap_gate) if self.part_size == 1: yield acquaint(*qubits) @@ -86,7 +88,7 @@ def decompose_complete(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_ yield acquaint(*qubits[x : x + 2]) yield swap_gate(*qubits[x : x + 2]) - def decompose_matching(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def decompose_matching(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: swap_gate = SwapPermutationGate(self.swap_gate) for k in range(-self.part_size + 1, self.part_size): for x in range(abs(k), 2 * self.part_size - abs(k), 2): @@ -95,7 +97,7 @@ def decompose_matching(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_ else: yield acquaint(*qubits[x : x + 2]) - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE: if len(qubits) != 2 * self.part_size: raise ValueError('len(qubits) != 2 * self.part_size') if self.subgraph == BipartiteGraphType.COMPLETE: @@ -122,7 +124,7 @@ def permutation(self) -> Dict[int, int]: return dict(enumerate(range(2 * self.part_size))) raise NotImplementedError(str(self.subgraph) + 'not implemented') - def _circuit_diagram_info_(self, args: 'cirq.CircuitDiagramInfoArgs') -> Tuple[str, ...]: + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]: qubit_count = 2 * self.part_size if args.known_qubit_count not in (None, qubit_count): raise ValueError('args.known_qubit_count not in (None, 2 * self.part_size)') diff --git a/cirq-core/cirq/contrib/acquaintance/devices.py b/cirq-core/cirq/contrib/acquaintance/devices.py index fef7994fe3e..2dde6bb7525 100644 --- a/cirq-core/cirq/contrib/acquaintance/devices.py +++ b/cirq-core/cirq/contrib/acquaintance/devices.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc from typing import TYPE_CHECKING, Union @@ -30,7 +32,7 @@ class AcquaintanceDevice(devices.Device, metaclass=abc.ABCMeta): gate_types = (AcquaintanceOpportunityGate, PermutationGate) - def validate_operation(self, operation: 'cirq.Operation') -> None: + def validate_operation(self, operation: cirq.Operation) -> None: if not ( isinstance(operation, ops.GateOperation) and isinstance(operation.gate, self.gate_types) ): diff --git a/cirq-core/cirq/contrib/acquaintance/executor.py b/cirq-core/cirq/contrib/acquaintance/executor.py index 440a1052867..1604799b390 100644 --- a/cirq-core/cirq/contrib/acquaintance/executor.py +++ b/cirq-core/cirq/contrib/acquaintance/executor.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc from collections import defaultdict from typing import DefaultDict, Dict, Iterator, Optional, Sequence, TYPE_CHECKING @@ -42,7 +44,7 @@ class ExecutionStrategy(metaclass=abc.ABCMeta): @property @abc.abstractmethod - def device(self) -> 'cirq.Device': + def device(self) -> cirq.Device: """The device for which the executed acquaintance strategy should be valid. """ @@ -54,8 +56,8 @@ def initial_mapping(self) -> LogicalMapping: @abc.abstractmethod def get_operations( - self, indices: Sequence[LogicalIndex], qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': + self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid] + ) -> cirq.OP_TREE: """Gets the logical operations to apply to qubits.""" def __call__(self, *args, **kwargs): @@ -97,13 +99,13 @@ def __init__(self, execution_strategy: ExecutionStrategy) -> None: self._mapping = execution_strategy.initial_mapping.copy() def __call__( - self, circuit: circuits.AbstractCircuit, context: Optional['cirq.TransformerContext'] = None + self, circuit: circuits.AbstractCircuit, context: Optional[cirq.TransformerContext] = None ) -> circuits.Circuit: """Executes an acquaintance strategy using cirq.map_operations_and_unroll and mutates initial mapping. Args: - circuit: 'cirq.Circuit' input circuit to transform. + circuit: `cirq.Circuit` input circuit to transform. context: `cirq.TransformerContext` storing common configurable options for transformers. @@ -126,7 +128,7 @@ def __call__( def mapping(self) -> LogicalMapping: return self._mapping - def _map_func(self, op: 'cirq.Operation', index) -> 'cirq.OP_TREE': + def _map_func(self, op: cirq.Operation, index) -> cirq.OP_TREE: if isinstance(op.gate, AcquaintanceOpportunityGate): logical_indices = tuple(self._mapping[q] for q in op.qubits) logical_operations = self.execution_strategy.get_operations(logical_indices, op.qubits) @@ -150,17 +152,13 @@ class AcquaintanceOperation(ops.GateOperation): logical indices on a particular set of physical qubits. """ - def __init__( - self, qubits: Sequence['cirq.Qid'], logical_indices: Sequence[LogicalIndex] - ) -> None: + def __init__(self, qubits: Sequence[cirq.Qid], logical_indices: Sequence[LogicalIndex]) -> None: if len(logical_indices) != len(qubits): raise ValueError('len(logical_indices) != len(qubits)') super().__init__(AcquaintanceOpportunityGate(num_qubits=len(qubits)), qubits) self.logical_indices: LogicalIndexSequence = logical_indices - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: wire_symbols = tuple(f'({i})' for i in self.logical_indices) return protocols.CircuitDiagramInfo(wire_symbols=wire_symbols) @@ -176,7 +174,7 @@ def __init__( self, gates: LogicalGates, initial_mapping: LogicalMapping, - device: Optional['cirq.Device'] = None, + device: Optional[cirq.Device] = None, ) -> None: """Inits GreedyExecutionStrategy. @@ -202,12 +200,12 @@ def initial_mapping(self) -> LogicalMapping: return self._initial_mapping @property - def device(self) -> 'cirq.Device': + def device(self) -> cirq.Device: return self._device def get_operations( - self, indices: Sequence[LogicalIndex], qubits: Sequence['cirq.Qid'] - ) -> Iterator['cirq.OP_TREE']: + self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid] + ) -> Iterator[cirq.OP_TREE]: index_set = frozenset(indices) if index_set in self.index_set_to_gates: gates = self.index_set_to_gates.pop(index_set) diff --git a/cirq-core/cirq/contrib/acquaintance/gates.py b/cirq-core/cirq/contrib/acquaintance/gates.py index e8b08e638d5..8f9c469f7d1 100644 --- a/cirq-core/cirq/contrib/acquaintance/gates.py +++ b/cirq-core/cirq/contrib/acquaintance/gates.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import functools import itertools import math @@ -41,13 +43,11 @@ def operations_to_part_lens( - qubit_order: Sequence['cirq.Qid'], op_tree: 'cirq.OP_TREE' + qubit_order: Sequence[cirq.Qid], op_tree: cirq.OP_TREE ) -> Tuple[int, ...]: qubit_sort_key = functools.partial(operator.indexOf, qubit_order) op_parts = [tuple(sorted(op.qubits, key=qubit_sort_key)) for op in ops.flatten_op_tree(op_tree)] - singletons: List[Tuple['cirq.Qid', ...]] = [ - (q,) for q in set(qubit_order).difference(*op_parts) - ] + singletons: List[Tuple[cirq.Qid, ...]] = [(q,) for q in set(qubit_order).difference(*op_parts)] part_sort_key = lambda p: min(qubit_sort_key(q) for q in p) parts = tuple(tuple(part) for part in sorted(singletons + op_parts, key=part_sort_key)) @@ -71,7 +71,7 @@ def __repr__(self) -> str: f'num_qubits={self.num_qubits()!r})' ) - def _circuit_diagram_info_(self, args: 'cirq.CircuitDiagramInfoArgs') -> Iterable[str]: + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Iterable[str]: wire_symbol = '█' if args.use_unicode_characters else 'Acq' wire_symbols = (wire_symbol,) * self.num_qubits() return wire_symbols @@ -80,7 +80,7 @@ def num_qubits(self) -> int: return self._num_qubits -def acquaint(*qubits) -> 'cirq.Operation': +def acquaint(*qubits) -> cirq.Operation: return AcquaintanceOpportunityGate(len(qubits)).on(*qubits) @@ -96,14 +96,14 @@ def acquaint(*qubits) -> 'cirq.Operation': ) -def new_layers(**kwargs: List['cirq.Operation']) -> Layers: +def new_layers(**kwargs: List[cirq.Operation]) -> Layers: return Layers._make(kwargs.get(field, []) for field in Layers._fields) def acquaint_insides( - swap_gate: 'cirq.Gate', - acquaintance_gate: 'cirq.Operation', - qubits: Sequence['cirq.Qid'], + swap_gate: cirq.Gate, + acquaintance_gate: cirq.Operation, + qubits: Sequence[cirq.Qid], before: bool, layers: Layers, mapping: Dict[ops.Qid, int], @@ -153,10 +153,10 @@ def _get_max_reach(size: int, round_up: bool = True) -> int: def acquaint_and_shift( - parts: Tuple[List['cirq.Qid'], List['cirq.Qid']], + parts: Tuple[List[cirq.Qid], List[cirq.Qid]], layers: Layers, acquaintance_size: Optional[int], - swap_gate: 'cirq.Gate', + swap_gate: cirq.Gate, mapping: Dict[ops.Qid, int], ): """Acquaints and shifts a pair of lists of qubits. The first part is @@ -277,7 +277,7 @@ def __init__( self, part_lens: Sequence[int], acquaintance_size: Optional[int] = 0, - swap_gate: 'cirq.Gate' = ops.SWAP, + swap_gate: cirq.Gate = ops.SWAP, ) -> None: super().__init__(sum(part_lens), swap_gate) if len(part_lens) < 2: @@ -285,7 +285,7 @@ def __init__( self.part_lens = tuple(part_lens) self.acquaintance_size = acquaintance_size - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: qubit_to_position = {q: i for i, q in enumerate(qubits)} mapping = dict(qubit_to_position) parts = [] @@ -333,9 +333,7 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: if final_gate: yield final_gate(*qubits) - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: wire_symbol = '×' if args.use_unicode_characters else 'swap' wire_symbols = tuple( wire_symbol + f'({part_index},{qubit_index})' @@ -346,11 +344,11 @@ def _circuit_diagram_info_( @staticmethod def from_operations( - qubit_order: Sequence['cirq.Qid'], - operations: Sequence['cirq.Operation'], + qubit_order: Sequence[cirq.Qid], + operations: Sequence[cirq.Operation], acquaintance_size: Optional[int] = 0, - swap_gate: 'cirq.Gate' = ops.SWAP, - ) -> 'SwapNetworkGate': + swap_gate: cirq.Gate = ops.SWAP, + ) -> SwapNetworkGate: part_sizes = operations_to_part_lens(qubit_order, operations) return SwapNetworkGate(part_sizes, acquaintance_size, swap_gate) diff --git a/cirq-core/cirq/contrib/acquaintance/inspection_utils.py b/cirq-core/cirq/contrib/acquaintance/inspection_utils.py index 584db70251c..70fc8fc1f9c 100644 --- a/cirq-core/cirq/contrib/acquaintance/inspection_utils.py +++ b/cirq-core/cirq/contrib/acquaintance/inspection_utils.py @@ -12,16 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import FrozenSet, Iterator, Sequence, Set, TYPE_CHECKING from cirq import devices from cirq.contrib import circuitdag from cirq.contrib.acquaintance.executor import AcquaintanceOperation, ExecutionStrategy from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates -from cirq.contrib.acquaintance.permutation import LogicalIndex, LogicalMapping if TYPE_CHECKING: import cirq + from cirq.contrib.acquaintance.permutation import LogicalIndex, LogicalMapping class LogicalAnnotator(ExecutionStrategy): @@ -40,16 +42,16 @@ def initial_mapping(self) -> LogicalMapping: return self._initial_mapping @property - def device(self) -> 'cirq.Device': + def device(self) -> cirq.Device: return devices.UNCONSTRAINED_DEVICE def get_operations( - self, indices: Sequence[LogicalIndex], qubits: Sequence['cirq.Qid'] - ) -> Iterator['cirq.OP_TREE']: + self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid] + ) -> Iterator[cirq.OP_TREE]: yield AcquaintanceOperation(qubits, indices) -def get_acquaintance_dag(strategy: 'cirq.Circuit', initial_mapping: LogicalMapping): +def get_acquaintance_dag(strategy: cirq.Circuit, initial_mapping: LogicalMapping): strategy = strategy.copy() expose_acquaintance_gates(strategy) LogicalAnnotator(initial_mapping)(strategy) @@ -63,7 +65,7 @@ def get_acquaintance_dag(strategy: 'cirq.Circuit', initial_mapping: LogicalMappi def get_logical_acquaintance_opportunities( - strategy: 'cirq.Circuit', initial_mapping: LogicalMapping + strategy: cirq.Circuit, initial_mapping: LogicalMapping ) -> Set[FrozenSet[LogicalIndex]]: acquaintance_dag = get_acquaintance_dag(strategy, initial_mapping) logical_acquaintance_opportunities = set() diff --git a/cirq-core/cirq/contrib/acquaintance/mutation_utils.py b/cirq-core/cirq/contrib/acquaintance/mutation_utils.py index 48ca8aa8f16..9206d824770 100644 --- a/cirq-core/cirq/contrib/acquaintance/mutation_utils.py +++ b/cirq-core/cirq/contrib/acquaintance/mutation_utils.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import collections from typing import cast, Dict, List, Optional, Sequence, TYPE_CHECKING, Union @@ -26,7 +28,7 @@ STRATEGY_GATE = Union[AcquaintanceOpportunityGate, PermutationGate] -def rectify_acquaintance_strategy(circuit: 'cirq.Circuit', acquaint_first: bool = True) -> None: +def rectify_acquaintance_strategy(circuit: cirq.Circuit, acquaint_first: bool = True) -> None: """Splits moments so that they contain either only acquaintance or permutation gates. Orders resulting moments so that the first one is of the same type as the previous one. @@ -55,10 +57,10 @@ def rectify_acquaintance_strategy(circuit: 'cirq.Circuit', acquaint_first: bool def replace_acquaintance_with_swap_network( - circuit: 'cirq.Circuit', - qubit_order: Sequence['cirq.Qid'], + circuit: cirq.Circuit, + qubit_order: Sequence[cirq.Qid], acquaintance_size: Optional[int] = 0, - swap_gate: 'cirq.Gate' = ops.SWAP, + swap_gate: cirq.Gate = ops.SWAP, ) -> bool: """Replace every rectified moment with acquaintance gates with a generalized swap network. @@ -104,10 +106,10 @@ def __init__(self): not get_acquaintance_size(op) or isinstance(op.gate, AcquaintanceOpportunityGate) ) - def optimize_circuit(self, circuit: 'cirq.Circuit') -> None: + def optimize_circuit(self, circuit: cirq.Circuit) -> None: circuit._moments = [*transformers.expand_composite(circuit, no_decomp=self.no_decomp)] - def __call__(self, circuit: 'cirq.Circuit') -> None: + def __call__(self, circuit: cirq.Circuit) -> None: self.optimize_circuit(circuit) diff --git a/cirq-core/cirq/contrib/acquaintance/optimizers.py b/cirq-core/cirq/contrib/acquaintance/optimizers.py index 3cd0c5ebccc..e655d6993a1 100644 --- a/cirq-core/cirq/contrib/acquaintance/optimizers.py +++ b/cirq-core/cirq/contrib/acquaintance/optimizers.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import cast, FrozenSet, List, Sequence, Set, TYPE_CHECKING from cirq import circuits @@ -24,7 +26,7 @@ import cirq -def remove_redundant_acquaintance_opportunities(strategy: 'cirq.Circuit') -> int: +def remove_redundant_acquaintance_opportunities(strategy: cirq.Circuit) -> int: """Removes redundant acquaintance opportunities.""" qubits = sorted(strategy.all_qubits()) @@ -34,11 +36,11 @@ def remove_redundant_acquaintance_opportunities(strategy: 'cirq.Circuit') -> int annotated_strategy = strategy.copy() LogicalAnnotator(mapping)(annotated_strategy) - new_moments: List['cirq.Moment'] = [] + new_moments: List[cirq.Moment] = [] acquaintance_opps: Set[FrozenSet[int]] = set() n_removed = 0 for moment in annotated_strategy: - new_moment: List['cirq.Operation'] = [] + new_moment: List[cirq.Operation] = [] for op in moment: if isinstance(op, AcquaintanceOperation): opp = frozenset(cast(Sequence[int], op.logical_indices)) diff --git a/cirq-core/cirq/contrib/acquaintance/permutation.py b/cirq-core/cirq/contrib/acquaintance/permutation.py index 86c6995caa6..89583e17d54 100644 --- a/cirq-core/cirq/contrib/acquaintance/permutation.py +++ b/cirq-core/cirq/contrib/acquaintance/permutation.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc from types import NotImplementedType from typing import ( @@ -51,7 +53,7 @@ class PermutationGate(ops.Gate, metaclass=abc.ABCMeta): qubits (e.g. SWAP or fermionic swap). """ - def __init__(self, num_qubits: int, swap_gate: 'cirq.Gate' = ops.SWAP) -> None: + def __init__(self, num_qubits: int, swap_gate: cirq.Gate = ops.SWAP) -> None: self._num_qubits = num_qubits self.swap_gate = swap_gate @@ -64,7 +66,7 @@ def permutation(self) -> Dict[int, int]: the s[i]-th element.""" def update_mapping( - self, mapping: Dict[ops.Qid, LogicalIndex], keys: Sequence['cirq.Qid'] + self, mapping: Dict[ops.Qid, LogicalIndex], keys: Sequence[cirq.Qid] ) -> None: """Updates a mapping (in place) from qubits to logical indices. @@ -96,8 +98,8 @@ def validate_permutation(permutation: Dict[int, int], n_elements: Optional[int] raise IndexError('key is out of bounds.') def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> Union[str, Iterable[str], 'cirq.CircuitDiagramInfo']: + self, args: cirq.CircuitDiagramInfoArgs + ) -> Union[str, Iterable[str], cirq.CircuitDiagramInfo]: if args.known_qubit_count is None: return NotImplemented permutation = self.permutation() @@ -118,14 +120,12 @@ def __init__(self, indices): def num_qubits(self) -> int: return self._num_qubits - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: wire_symbols = tuple('' if i is None else str(i) for i in self.indices) return protocols.CircuitDiagramInfo(wire_symbols, connected=False) -def display_mapping(circuit: 'cirq.Circuit', initial_mapping: LogicalMapping) -> None: +def display_mapping(circuit: cirq.Circuit, initial_mapping: LogicalMapping) -> None: """Inserts display gates between moments to indicate the mapping throughout the circuit.""" qubits = sorted(circuit.all_qubits()) @@ -147,13 +147,13 @@ def display_mapping(circuit: 'cirq.Circuit', initial_mapping: LogicalMapping) -> class SwapPermutationGate(PermutationGate): """Generic swap gate.""" - def __init__(self, swap_gate: 'cirq.Gate' = ops.SWAP): + def __init__(self, swap_gate: cirq.Gate = ops.SWAP): super().__init__(2, swap_gate) def permutation(self) -> Dict[int, int]: return {0: 1, 1: 0} - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: yield self.swap_gate(*qubits) def __repr__(self) -> str: @@ -186,7 +186,7 @@ class LinearPermutationGate(PermutationGate): sorting network.""" def __init__( - self, num_qubits: int, permutation: Dict[int, int], swap_gate: 'cirq.Gate' = ops.SWAP + self, num_qubits: int, permutation: Dict[int, int], swap_gate: cirq.Gate = ops.SWAP ) -> None: """Initializes a linear permutation gate. @@ -202,7 +202,7 @@ def __init__( def permutation(self) -> Dict[int, int]: return self._permutation - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: swap_gate = SwapPermutationGate(self.swap_gate) n_qubits = len(qubits) mapping = {i: self._permutation.get(i, i) for i in range(n_qubits)} @@ -238,7 +238,7 @@ def __pow__(self, exponent): return NotImplemented -def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: 'cirq.OP_TREE') -> None: +def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: cirq.OP_TREE) -> None: """Updates a mapping (in place) from qubits to logical indices according to a set of permutation gates. Any gates other than permutation gates are ignored. @@ -253,8 +253,8 @@ def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: 'cirq.OP_TR def get_logical_operations( - operations: 'cirq.OP_TREE', initial_mapping: Dict[ops.Qid, ops.Qid] -) -> Iterable['cirq.Operation']: + operations: cirq.OP_TREE, initial_mapping: Dict[ops.Qid, ops.Qid] +) -> Iterable[cirq.Operation]: """Gets the logical operations specified by the physical operations and initial mapping. @@ -300,10 +300,10 @@ def __init__(self, keep_swap_permutations: bool = True): not all([isinstance(op, ops.GateOperation), isinstance(op.gate, PermutationGate)]) ) - def optimize_circuit(self, circuit: 'cirq.Circuit') -> None: + def optimize_circuit(self, circuit: cirq.Circuit) -> None: circuit._moments = [*transformers.expand_composite(circuit, no_decomp=self.no_decomp)] - def __call__(self, circuit: 'cirq.Circuit') -> None: + def __call__(self, circuit: cirq.Circuit) -> None: self.optimize_circuit(circuit) @@ -311,7 +311,7 @@ def __call__(self, circuit: 'cirq.Circuit') -> None: DECOMPOSE_PERMUTATION_GATES = DecomposePermutationGates(keep_swap_permutations=False) -def return_to_initial_mapping(circuit: 'cirq.Circuit', swap_gate: 'cirq.Gate' = ops.SWAP) -> None: +def return_to_initial_mapping(circuit: cirq.Circuit, swap_gate: cirq.Gate = ops.SWAP) -> None: qubits = sorted(circuit.all_qubits()) n_qubits = len(qubits) @@ -323,7 +323,7 @@ def return_to_initial_mapping(circuit: 'cirq.Circuit', swap_gate: 'cirq.Gate' = circuit.append(returning_permutation_op) -def uses_consistent_swap_gate(circuit: 'cirq.Circuit', swap_gate: 'cirq.Gate') -> bool: +def uses_consistent_swap_gate(circuit: cirq.Circuit, swap_gate: cirq.Gate) -> bool: for op in circuit.all_operations(): if isinstance(op, ops.GateOperation) and isinstance(op.gate, PermutationGate): if op.gate.swap_gate != swap_gate: diff --git a/cirq-core/cirq/contrib/acquaintance/shift.py b/cirq-core/cirq/contrib/acquaintance/shift.py index 35040ad57aa..f89908f1576 100644 --- a/cirq-core/cirq/contrib/acquaintance/shift.py +++ b/cirq-core/cirq/contrib/acquaintance/shift.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import itertools from typing import Any, Dict, Iterator, Sequence, Tuple, TYPE_CHECKING @@ -26,7 +28,7 @@ class CircularShiftGate(PermutationGate): """Performs a cyclical permutation of the qubits to the left by a specified amount.""" - def __init__(self, num_qubits: int, shift: int, swap_gate: 'cirq.Gate' = ops.SWAP) -> None: + def __init__(self, num_qubits: int, shift: int, swap_gate: cirq.Gate = ops.SWAP) -> None: """Construct a circular shift gate. Args: @@ -47,7 +49,7 @@ def __repr__(self) -> str: def _value_equality_values_(self) -> Any: return self.shift, self.swap_gate, self.num_qubits() - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: n = len(qubits) left_shift = self.shift % n right_shift = n - left_shift @@ -58,7 +60,7 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: for k in range(i, j, 2): yield swap_gate(*qubits[k : k + 2]) - def _circuit_diagram_info_(self, args: 'cirq.CircuitDiagramInfoArgs') -> Tuple[str, ...]: + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]: if args.known_qubit_count is None: return NotImplemented # pragma: no cover direction_symbols = ('╲', '╱') if args.use_unicode_characters else ('\\', '/') diff --git a/cirq-core/cirq/contrib/acquaintance/shift_swap_network.py b/cirq-core/cirq/contrib/acquaintance/shift_swap_network.py index 5b3554ff74b..f4ee6951558 100644 --- a/cirq-core/cirq/contrib/acquaintance/shift_swap_network.py +++ b/cirq-core/cirq/contrib/acquaintance/shift_swap_network.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import functools import itertools from typing import Dict, Iterable, Iterator, Optional, Sequence, Tuple, TYPE_CHECKING @@ -51,7 +53,7 @@ def __init__( self, left_part_lens: Iterable[int], right_part_lens: Iterable[int], - swap_gate: 'cirq.Gate' = ops.SWAP, + swap_gate: cirq.Gate = ops.SWAP, ) -> None: self.part_lens = {'left': tuple(left_part_lens), 'right': tuple(right_part_lens)} @@ -65,7 +67,7 @@ def __init__( def acquaintance_size(self) -> int: return sum(max(self.part_lens[side]) for side in ('left', 'right')) - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: part_lens = list(itertools.chain(*(self.part_lens[side] for side in ('left', 'right')))) n_qubits = 0 @@ -110,7 +112,7 @@ def permutation(self) -> Dict[int, int]: ) ) - def _circuit_diagram_info_(self, args: 'cirq.CircuitDiagramInfoArgs') -> Tuple[str, ...]: + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]: qubit_count = self.qubit_count() assert args.known_qubit_count in (None, qubit_count) diff --git a/cirq-core/cirq/contrib/acquaintance/strategies/complete.py b/cirq-core/cirq/contrib/acquaintance/strategies/complete.py index c7307082e16..b2a3ef6ef18 100755 --- a/cirq-core/cirq/contrib/acquaintance/strategies/complete.py +++ b/cirq-core/cirq/contrib/acquaintance/strategies/complete.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Sequence, TYPE_CHECKING from cirq import circuits, ops @@ -26,8 +28,8 @@ def complete_acquaintance_strategy( - qubit_order: Sequence['cirq.Qid'], acquaintance_size: int = 0, swap_gate: 'cirq.Gate' = ops.SWAP -) -> 'cirq.Circuit': + qubit_order: Sequence[cirq.Qid], acquaintance_size: int = 0, swap_gate: cirq.Gate = ops.SWAP +) -> cirq.Circuit: """Returns an acquaintance strategy with can handle the given number of qubits. Args: diff --git a/cirq-core/cirq/contrib/acquaintance/strategies/cubic.py b/cirq-core/cirq/contrib/acquaintance/strategies/cubic.py index 6dc008e0f7d..c553c3a27ee 100644 --- a/cirq-core/cirq/contrib/acquaintance/strategies/cubic.py +++ b/cirq-core/cirq/contrib/acquaintance/strategies/cubic.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import itertools from typing import Iterable, Sequence, Tuple, TYPE_CHECKING, TypeVar @@ -35,8 +37,8 @@ def skip_and_wrap_around(items: Sequence[TItem]) -> Tuple[TItem, ...]: def cubic_acquaintance_strategy( - qubits: Iterable['cirq.Qid'], swap_gate: 'cirq.Gate' = ops.SWAP -) -> 'cirq.Circuit': + qubits: Iterable[cirq.Qid], swap_gate: cirq.Gate = ops.SWAP +) -> cirq.Circuit: """Acquaints every triple of qubits. Exploits the fact that in a simple linear swap network every pair of diff --git a/cirq-core/cirq/contrib/acquaintance/strategies/quartic_paired.py b/cirq-core/cirq/contrib/acquaintance/strategies/quartic_paired.py index de3c9f7fa7b..43e2db4ff24 100644 --- a/cirq-core/cirq/contrib/acquaintance/strategies/quartic_paired.py +++ b/cirq-core/cirq/contrib/acquaintance/strategies/quartic_paired.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import cast, Iterable, List, Sequence, Tuple, TYPE_CHECKING -from cirq import circuits, ops +from cirq import circuits from cirq.contrib.acquaintance.gates import acquaint, SwapNetworkGate from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates @@ -22,7 +24,7 @@ import cirq -def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence['cirq.Qid']]) -> List['cirq.Qid']: +def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence[cirq.Qid]]) -> List[cirq.Qid]: """Takes a sequence of qubit pairs and returns a sequence in which every pair is at distance two. @@ -33,7 +35,7 @@ def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence['cirq.Qid']]) -> L if set(len(qubit_pair) for qubit_pair in qubit_pairs) != set((2,)): raise ValueError('set(len(qubit_pair) for qubit_pair in qubit_pairs) != set((2,))') n_pairs = len(qubit_pairs) - qubits: List['cirq.Qid'] = [] + qubits: List[cirq.Qid] = [] for i in range(0, 2 * (n_pairs // 2), 2): qubits += [ qubit_pairs[i][0], @@ -47,15 +49,15 @@ def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence['cirq.Qid']]) -> L def quartic_paired_acquaintance_strategy( - qubit_pairs: Iterable[Tuple['cirq.Qid', ops.Qid]], -) -> Tuple['cirq.Circuit', Sequence['cirq.Qid']]: + qubit_pairs: Iterable[Tuple[cirq.Qid, cirq.Qid]], +) -> Tuple[cirq.Circuit, Sequence[cirq.Qid]]: """Acquaintance strategy for pairs of pairs. Implements UpCCGSD ansatz from arXiv:1810.02327. """ qubit_pairs = tuple( - cast(Tuple['cirq.Qid', ops.Qid], tuple(qubit_pair)) for qubit_pair in qubit_pairs + cast(Tuple['cirq.Qid', 'cirq.Qid'], tuple(qubit_pair)) for qubit_pair in qubit_pairs ) qubits = qubit_pairs_to_qubit_order(qubit_pairs) n_qubits = len(qubits) diff --git a/cirq-core/cirq/contrib/acquaintance/topological_sort.py b/cirq-core/cirq/contrib/acquaintance/topological_sort.py index 5defe1e7798..d2094d155d2 100644 --- a/cirq-core/cirq/contrib/acquaintance/topological_sort.py +++ b/cirq-core/cirq/contrib/acquaintance/topological_sort.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import operator import random from typing import Any, Callable, cast, Iterable, TYPE_CHECKING @@ -25,8 +27,8 @@ def is_topologically_sorted( - dag: 'cirq.contrib.CircuitDag', - operations: 'cirq.OP_TREE', + dag: cirq.contrib.CircuitDag, + operations: cirq.OP_TREE, equals: Callable[[ops.Operation, ops.Operation], bool] = operator.eq, ) -> bool: """Whether a given order of operations is consistent with the DAG. diff --git a/cirq-core/cirq/contrib/bayesian_network/bayesian_network_gate.py b/cirq-core/cirq/contrib/bayesian_network/bayesian_network_gate.py index c6ae5e47bd3..82cdaa49737 100644 --- a/cirq-core/cirq/contrib/bayesian_network/bayesian_network_gate.py +++ b/cirq-core/cirq/contrib/bayesian_network/bayesian_network_gate.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import math from typing import Any, cast, Dict, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union @@ -158,7 +160,7 @@ def __init__( raise ValueError('Conditional prob should be between 0 and 1.') self._arc_probs = arc_probs - def _decompose_(self, qubits: Sequence['raw_types.Qid']) -> Iterator['cirq.OP_TREE']: + def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]: parameter_names = [init_prob[0] for init_prob in self._init_probs] qubit_map = dict(zip(parameter_names, qubits)) @@ -188,7 +190,7 @@ def _from_json_dict_( init_probs: List[List[Union[str, Optional[float]]]], arc_probs: List[List[Union[str, List[str], List[float]]]], **kwargs, - ) -> 'BayesianNetworkGate': + ) -> BayesianNetworkGate: converted_init_probs = cast( List[Tuple[str, Optional[float]]], [(param, init_prob) for param, init_prob in init_probs], diff --git a/cirq-core/cirq/contrib/circuitdag/circuit_dag.py b/cirq-core/cirq/contrib/circuitdag/circuit_dag.py index 24eae58a453..e1ea0ca8f09 100644 --- a/cirq-core/cirq/contrib/circuitdag/circuit_dag.py +++ b/cirq-core/cirq/contrib/circuitdag/circuit_dag.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import functools from typing import Any, Callable, cast, Dict, Generic, Iterator, TypeVar @@ -48,7 +50,7 @@ def __lt__(self, other): return id(self) < id(other) -def _disjoint_qubits(op1: 'cirq.Operation', op2: 'cirq.Operation') -> bool: +def _disjoint_qubits(op1: cirq.Operation, op2: cirq.Operation) -> bool: """Returns true only if the operations have qubits in common.""" return not set(op1.qubits) & set(op2.qubits) @@ -70,7 +72,7 @@ class CircuitDag(networkx.DiGraph): def __init__( self, - can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits, + can_reorder: Callable[[cirq.Operation, cirq.Operation], bool] = _disjoint_qubits, incoming_graph_data: Any = None, ) -> None: """Initializes a CircuitDag. @@ -91,27 +93,27 @@ def __init__( self.can_reorder = can_reorder @staticmethod - def make_node(op: 'cirq.Operation') -> Unique: + def make_node(op: cirq.Operation) -> Unique: return Unique(op) @staticmethod def from_circuit( circuit: cirq.Circuit, - can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits, - ) -> 'CircuitDag': + can_reorder: Callable[[cirq.Operation, cirq.Operation], bool] = _disjoint_qubits, + ) -> CircuitDag: return CircuitDag.from_ops(circuit.all_operations(), can_reorder=can_reorder) @staticmethod def from_ops( - *operations: 'cirq.OP_TREE', - can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits, - ) -> 'CircuitDag': + *operations: cirq.OP_TREE, + can_reorder: Callable[[cirq.Operation, cirq.Operation], bool] = _disjoint_qubits, + ) -> CircuitDag: dag = CircuitDag(can_reorder=can_reorder) for op in ops.flatten_op_tree(operations): dag.append(cast(ops.Operation, op)) return dag - def append(self, op: 'cirq.Operation') -> None: + def append(self, op: cirq.Operation) -> None: new_node = self.make_node(op) for node in list(self.nodes()): if not self.can_reorder(node.val, op): @@ -140,21 +142,21 @@ def __ne__(self, other): __hash__ = None # type: ignore - def ordered_nodes(self) -> Iterator[Unique['cirq.Operation']]: + def ordered_nodes(self) -> Iterator[Unique[cirq.Operation]]: if not self.nodes(): return g = self.copy() - def get_root_node(some_node: Unique['cirq.Operation']) -> Unique['cirq.Operation']: + def get_root_node(some_node: Unique[cirq.Operation]) -> Unique[cirq.Operation]: pred = g.pred while pred[some_node]: some_node = next(iter(pred[some_node])) return some_node - def get_first_node() -> Unique['cirq.Operation']: + def get_first_node() -> Unique[cirq.Operation]: return get_root_node(next(iter(g.nodes()))) - def get_next_node(succ: networkx.classes.coreviews.AtlasView) -> Unique['cirq.Operation']: + def get_next_node(succ: networkx.classes.coreviews.AtlasView) -> Unique[cirq.Operation]: if succ: return get_root_node(next(iter(succ))) @@ -171,7 +173,7 @@ def get_next_node(succ: networkx.classes.coreviews.AtlasView) -> Unique['cirq.Op node = get_next_node(succ) - def all_operations(self) -> Iterator['cirq.Operation']: + def all_operations(self) -> Iterator[cirq.Operation]: return (node.val for node in self.ordered_nodes()) def all_qubits(self): @@ -181,8 +183,8 @@ def to_circuit(self) -> cirq.Circuit: return cirq.Circuit(self.all_operations(), strategy=cirq.InsertStrategy.EARLIEST) def findall_nodes_until_blocked( - self, is_blocker: Callable[['cirq.Operation'], bool] - ) -> Iterator[Unique['cirq.Operation']]: + self, is_blocker: Callable[[cirq.Operation], bool] + ) -> Iterator[Unique[cirq.Operation]]: """Finds all nodes before blocking ones. Args: diff --git a/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator.py b/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator.py index 5e6f918c5d5..4e5bde95090 100644 --- a/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator.py +++ b/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Any, Dict, Generic, Sequence, Type, TYPE_CHECKING import numpy as np @@ -47,7 +49,7 @@ def __init__( self, state_type: Type[TSimulationState], *, - noise: 'cirq.NOISE_MODEL_LIKE' = None, + noise: cirq.NOISE_MODEL_LIKE = None, split_untangled_states: bool = False, ): """Initializes a CustomStateSimulator. @@ -63,24 +65,24 @@ def __init__( def _create_simulator_trial_result( self, - params: 'cirq.ParamResolver', + params: cirq.ParamResolver, measurements: Dict[str, np.ndarray], - final_simulator_state: 'cirq.SimulationStateBase[TSimulationState]', - ) -> 'CustomStateTrialResult[TSimulationState]': + final_simulator_state: cirq.SimulationStateBase[TSimulationState], + ) -> CustomStateTrialResult[TSimulationState]: return CustomStateTrialResult( params, measurements, final_simulator_state=final_simulator_state ) def _create_step_result( - self, sim_state: 'cirq.SimulationStateBase[TSimulationState]' - ) -> 'CustomStateStepResult[TSimulationState]': + self, sim_state: cirq.SimulationStateBase[TSimulationState] + ) -> CustomStateStepResult[TSimulationState]: return CustomStateStepResult(sim_state) def _create_partial_simulation_state( self, initial_state: Any, - qubits: Sequence['cirq.Qid'], - classical_data: 'cirq.ClassicalDataStore', + qubits: Sequence[cirq.Qid], + classical_data: cirq.ClassicalDataStore, ) -> TSimulationState: return self.state_type( initial_state=initial_state, qubits=qubits, classical_data=classical_data diff --git a/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator_test.py b/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator_test.py index 8f2f7616eaa..502b85b7c1c 100644 --- a/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator_test.py +++ b/cirq-core/cirq/contrib/custom_simulators/custom_state_simulator_test.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import List, Sequence, Tuple import numpy as np @@ -25,10 +27,10 @@ class ComputationalBasisState(cirq.qis.QuantumStateRepresentation): def __init__(self, initial_state: List[int]): self.basis = initial_state - def copy(self, deep_copy_buffers: bool = True) -> 'ComputationalBasisState': + def copy(self, deep_copy_buffers: bool = True) -> ComputationalBasisState: return ComputationalBasisState(self.basis) # pragma: no cover - def measure(self, axes: Sequence[int], seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None): + def measure(self, axes: Sequence[int], seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None): return [self.basis[i] for i in axes] @@ -137,18 +139,18 @@ class ComputationalBasisProductState(cirq.qis.QuantumStateRepresentation): def __init__(self, initial_state: List[int]): self.basis = initial_state - def copy(self, deep_copy_buffers: bool = True) -> 'ComputationalBasisProductState': + def copy(self, deep_copy_buffers: bool = True) -> ComputationalBasisProductState: return ComputationalBasisProductState(self.basis) - def measure(self, axes: Sequence[int], seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None): + def measure(self, axes: Sequence[int], seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None): return [self.basis[i] for i in axes] - def kron(self, other: 'ComputationalBasisProductState') -> 'ComputationalBasisProductState': + def kron(self, other: ComputationalBasisProductState) -> ComputationalBasisProductState: return ComputationalBasisProductState(self.basis + other.basis) def factor( self, axes: Sequence[int], *, validate=True, atol=1e-07 - ) -> Tuple['ComputationalBasisProductState', 'ComputationalBasisProductState']: + ) -> Tuple[ComputationalBasisProductState, ComputationalBasisProductState]: extracted = ComputationalBasisProductState( [self.basis[i] for i in axes] ) # pragma: no cover @@ -157,7 +159,7 @@ def factor( ) # pragma: no cover return extracted, remainder # pragma: no cover - def reindex(self, axes: Sequence[int]) -> 'ComputationalBasisProductState': + def reindex(self, axes: Sequence[int]) -> ComputationalBasisProductState: return ComputationalBasisProductState([self.basis[i] for i in axes]) @property diff --git a/cirq-core/cirq/contrib/graph_device/graph_device.py b/cirq-core/cirq/contrib/graph_device/graph_device.py index e9c1f67fe69..5b742fe8c28 100644 --- a/cirq-core/cirq/contrib/graph_device/graph_device.py +++ b/cirq-core/cirq/contrib/graph_device/graph_device.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc import itertools from typing import cast, Iterable, Optional, Tuple, TYPE_CHECKING @@ -150,7 +152,7 @@ def __init__( self.crosstalk_graph = crosstalk_graph @property - def qubits(self) -> Tuple['cirq.Qid', ...]: + def qubits(self) -> Tuple[cirq.Qid, ...]: return cast(Tuple['cirq.Qid', ...], tuple(sorted(self.device_graph.vertices))) @property @@ -192,7 +194,7 @@ def validate_crosstalk( ): validator(operation, *crosstalk_operations) - def validate_moment(self, moment: 'cirq.Moment'): + def validate_moment(self, moment: cirq.Moment): super().validate_moment(moment) ops = moment.operations for i, op in enumerate(ops): diff --git a/cirq-core/cirq/contrib/noise_models/noise_models.py b/cirq-core/cirq/contrib/noise_models/noise_models.py index 014dab0d85a..6fb8df7ec7f 100644 --- a/cirq-core/cirq/contrib/noise_models/noise_models.py +++ b/cirq-core/cirq/contrib/noise_models/noise_models.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Sequence, TYPE_CHECKING from cirq import circuits, devices, ops, value @@ -40,7 +42,7 @@ def __init__(self, depol_prob: float, prepend: bool = False): self.qubit_noise_gate = ops.DepolarizingChannel(depol_prob) self._prepend = prepend - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): if validate_all_measurements(moment) or self.is_virtual_moment(moment): # pragma: no cover return moment @@ -76,7 +78,7 @@ def __init__(self, bitflip_prob: float, prepend: bool = True): self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob) self._prepend = prepend - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): if self.is_virtual_moment(moment): return moment if validate_all_measurements(moment): @@ -113,7 +115,7 @@ def __init__(self, decay_prob: float, prepend: bool = True): self.readout_decay_gate = ops.AmplitudeDampingChannel(decay_prob) self._prepend = prepend - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): if self.is_virtual_moment(moment): return moment if validate_all_measurements(moment): @@ -146,7 +148,7 @@ def __init__(self, depol_prob: float, bitflip_prob: float): self.qubit_noise_gate = ops.DepolarizingChannel(depol_prob) self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob) - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): if validate_all_measurements(moment): return [circuits.Moment(self.readout_noise_gate(q) for q in system_qubits), moment] return [moment, circuits.Moment(self.qubit_noise_gate(q) for q in system_qubits)] @@ -176,7 +178,7 @@ def __init__(self, depol_prob: float, bitflip_prob: float, decay_prob: float): self.readout_noise_gate = ops.BitFlipChannel(bitflip_prob) self.readout_decay_gate = ops.AmplitudeDampingChannel(decay_prob) - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): if validate_all_measurements(moment): return [ circuits.Moment(self.readout_decay_gate(q) for q in system_qubits), diff --git a/cirq-core/cirq/contrib/paulistring/clifford_target_gateset.py b/cirq-core/cirq/contrib/paulistring/clifford_target_gateset.py index 32deed97457..2f69c65f8d5 100644 --- a/cirq-core/cirq/contrib/paulistring/clifford_target_gateset.py +++ b/cirq-core/cirq/contrib/paulistring/clifford_target_gateset.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from enum import Enum from types import NotImplementedType from typing import cast, List, Type, TYPE_CHECKING, Union @@ -25,7 +27,7 @@ def _matrix_to_clifford_op( - mat: np.ndarray, qubit: 'cirq.Qid', *, atol: float + mat: np.ndarray, qubit: cirq.Qid, *, atol: float ) -> Union[ops.Operation, NotImplementedType]: rotations = transformers.single_qubit_matrix_to_pauli_rotations(mat, atol) clifford_gate = ops.SingleQubitCliffordGate.I @@ -43,7 +45,7 @@ def _matrix_to_clifford_op( def _matrix_to_pauli_string_phasors( - mat: np.ndarray, qubit: 'cirq.Qid', *, keep_clifford: bool, atol: float + mat: np.ndarray, qubit: cirq.Qid, *, keep_clifford: bool, atol: float ) -> ops.OP_TREE: rotations = transformers.single_qubit_matrix_to_pauli_rotations(mat, atol) out_ops: List[ops.GateOperation] = [] @@ -95,7 +97,7 @@ def __init__( """ self.atol = atol self.single_qubit_target = single_qubit_target - gates: List[Union['cirq.Gate', Type['cirq.Gate']]] = [ops.CZ, ops.MeasurementGate] + gates: List[Union[cirq.Gate, Type[cirq.Gate]]] = [ops.CZ, ops.MeasurementGate] if single_qubit_target in [ self.SingleQubitTarget.SINGLE_QUBIT_CLIFFORDS, self.SingleQubitTarget.PAULI_STRING_PHASORS_AND_CLIFFORDS, @@ -109,8 +111,8 @@ def __init__( super().__init__(*gates) def _decompose_single_qubit_operation( - self, op: 'cirq.Operation', _ - ) -> Union[NotImplementedType, 'cirq.OP_TREE']: + self, op: cirq.Operation, _ + ) -> Union[NotImplementedType, cirq.OP_TREE]: if not protocols.has_unitary(op): return NotImplemented mat = protocols.unitary(op) @@ -126,8 +128,8 @@ def _decompose_single_qubit_operation( ) def _decompose_two_qubit_operation( - self, op: 'cirq.Operation', _ - ) -> Union[NotImplementedType, 'cirq.OP_TREE']: + self, op: cirq.Operation, _ + ) -> Union[NotImplementedType, cirq.OP_TREE]: if not protocols.has_unitary(op): return NotImplemented return transformers.two_qubit_matrix_to_cz_operations( @@ -139,10 +141,10 @@ def _decompose_two_qubit_operation( ) @property - def postprocess_transformers(self) -> List['cirq.TRANSFORMER']: + def postprocess_transformers(self) -> List[cirq.TRANSFORMER]: """List of transformers which should be run after decomposing individual operations.""" - def rewriter(o: 'cirq.CircuitOperation'): + def rewriter(o: cirq.CircuitOperation): result = self._decompose_single_qubit_operation(o, -1) return o.circuit.all_operations() if result is NotImplemented else result diff --git a/cirq-core/cirq/contrib/qcircuit/qcircuit_diagram.py b/cirq-core/cirq/contrib/qcircuit/qcircuit_diagram.py index 00d9219a7e5..3047be7cbd1 100644 --- a/cirq-core/cirq/contrib/qcircuit/qcircuit_diagram.py +++ b/cirq-core/cirq/contrib/qcircuit/qcircuit_diagram.py @@ -11,6 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import annotations + from typing import TYPE_CHECKING from cirq import circuits, ops @@ -23,7 +26,7 @@ import cirq -def qcircuit_qubit_namer(qubit: 'cirq.Qid') -> str: +def qcircuit_qubit_namer(qubit: cirq.Qid) -> str: """Returns the latex code for a QCircuit label of given qubit. Args: @@ -64,7 +67,7 @@ def _render(diagram: circuits.TextDiagramDrawer) -> str: def circuit_to_latex_using_qcircuit( - circuit: 'cirq.Circuit', qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT + circuit: cirq.Circuit, qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT ) -> str: """Returns a QCircuit-based latex diagram of the given circuit. diff --git a/cirq-core/cirq/contrib/quantum_volume/quantum_volume.py b/cirq-core/cirq/contrib/quantum_volume/quantum_volume.py index cbdb76555b1..c8ef92073b3 100644 --- a/cirq-core/cirq/contrib/quantum_volume/quantum_volume.py +++ b/cirq-core/cirq/contrib/quantum_volume/quantum_volume.py @@ -15,7 +15,7 @@ def generate_model_circuit( - num_qubits: int, depth: int, *, random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None + num_qubits: int, depth: int, *, random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None ) -> cirq.Circuit: """Generates a model circuit with the given number of qubits and depth. @@ -277,7 +277,7 @@ def compile_circuit( # Replace the PermutationGates with regular gates, so we don't proliferate # the routing implementation details to the compiler and the device itself. - def replace_swap_permutation_gate(op: 'cirq.Operation', _): + def replace_swap_permutation_gate(op: cirq.Operation, _): if isinstance(op.gate, cirq.contrib.acquaintance.SwapPermutationGate): return [op.gate.swap_gate.on(*op.qubits)] return op @@ -327,7 +327,7 @@ def prepare_circuits( num_qubits: int, depth: int, num_circuits: int, - random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None, ) -> List[Tuple[cirq.Circuit, List[int]]]: """Generates circuits and computes their heavy set. @@ -423,7 +423,7 @@ def calculate_quantum_volume( num_circuits: int, device_graph: nx.Graph, samplers: List[cirq.Sampler], - random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None, compiler: Optional[Callable[[cirq.Circuit], cirq.Circuit]] = None, repetitions=10_000, routing_attempts=30, diff --git a/cirq-core/cirq/contrib/quimb/mps_simulator.py b/cirq-core/cirq/contrib/quimb/mps_simulator.py index 713a8a9556e..bafb9a33dd5 100644 --- a/cirq-core/cirq/contrib/quimb/mps_simulator.py +++ b/cirq-core/cirq/contrib/quimb/mps_simulator.py @@ -17,6 +17,8 @@ https://arxiv.org/abs/2002.07730 """ +from __future__ import annotations + import dataclasses import math from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union @@ -58,10 +60,10 @@ class MPSSimulator( def __init__( self, - noise: 'cirq.NOISE_MODEL_LIKE' = None, - seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + noise: cirq.NOISE_MODEL_LIKE = None, + seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None, simulation_options: MPSOptions = MPSOptions(), - grouping: Optional[Dict['cirq.Qid', int]] = None, + grouping: Optional[Dict[cirq.Qid, int]] = None, ): """Creates instance of `MPSSimulator`. @@ -84,10 +86,10 @@ def __init__( def _create_partial_simulation_state( self, - initial_state: Union[int, 'MPSState'], - qubits: Sequence['cirq.Qid'], - classical_data: 'cirq.ClassicalDataStore', - ) -> 'MPSState': + initial_state: Union[int, MPSState], + qubits: Sequence[cirq.Qid], + classical_data: cirq.ClassicalDataStore, + ) -> MPSState: """Creates MPSState args for simulating the Circuit. Args: @@ -114,15 +116,15 @@ def _create_partial_simulation_state( classical_data=classical_data, ) - def _create_step_result(self, sim_state: 'cirq.SimulationStateBase[MPSState]'): + def _create_step_result(self, sim_state: cirq.SimulationStateBase[MPSState]): return MPSSimulatorStepResult(sim_state) def _create_simulator_trial_result( self, - params: 'cirq.ParamResolver', + params: cirq.ParamResolver, measurements: Dict[str, np.ndarray], - final_simulator_state: 'cirq.SimulationStateBase[MPSState]', - ) -> 'MPSTrialResult': + final_simulator_state: cirq.SimulationStateBase[MPSState], + ) -> MPSTrialResult: """Creates a single trial results with the measurements. Args: @@ -144,16 +146,16 @@ class MPSTrialResult(simulator_base.SimulationTrialResultBase['MPSState']): def __init__( self, - params: 'cirq.ParamResolver', + params: cirq.ParamResolver, measurements: Dict[str, np.ndarray], - final_simulator_state: 'cirq.SimulationStateBase[MPSState]', + final_simulator_state: cirq.SimulationStateBase[MPSState], ) -> None: super().__init__( params=params, measurements=measurements, final_simulator_state=final_simulator_state ) @property - def final_state(self) -> 'MPSState': + def final_state(self) -> MPSState: return self._get_merged_sim_state() def __str__(self) -> str: @@ -173,7 +175,7 @@ def _repr_pretty_(self, p: Any, cycle: bool): class MPSSimulatorStepResult(simulator_base.StepResultBase['MPSState']): """A `StepResult` that can perform measurements.""" - def __init__(self, sim_state: 'cirq.SimulationStateBase[MPSState]'): + def __init__(self, sim_state: cirq.SimulationStateBase[MPSState]): """Results of a step of the simulator. Attributes: sim_state: The qubit:SimulationState lookup for this step. @@ -309,7 +311,7 @@ def __str__(self) -> str: def _value_equality_values_(self) -> Any: return self._qid_shape, self._M, self._simulation_options, self._grouping - def copy(self, deep_copy_buffers: bool = True) -> '_MPSHandler': + def copy(self, deep_copy_buffers: bool = True) -> _MPSHandler: """Copies the object. Args: @@ -520,7 +522,7 @@ def _measure( return results def measure( - self, axes: Sequence[int], seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None + self, axes: Sequence[int], seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None ) -> List[int]: """Measures the MPS. @@ -533,10 +535,7 @@ def measure( return self._measure(axes, value.parse_random_state(seed)) def sample( - self, - axes: Sequence[int], - repetitions: int = 1, - seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + self, axes: Sequence[int], repetitions: int = 1, seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None ) -> np.ndarray: """Samples the MPS. @@ -564,12 +563,12 @@ class MPSState(SimulationState[_MPSHandler]): def __init__( self, *, - qubits: Sequence['cirq.Qid'], + qubits: Sequence[cirq.Qid], prng: np.random.RandomState, simulation_options: MPSOptions = MPSOptions(), - grouping: Optional[Dict['cirq.Qid', int]] = None, + grouping: Optional[Dict[cirq.Qid, int]] = None, initial_state: int = 0, - classical_data: Optional['cirq.ClassicalDataStore'] = None, + classical_data: Optional[cirq.ClassicalDataStore] = None, ): """Creates and MPSState @@ -623,7 +622,7 @@ def state_vector(self) -> np.ndarray: """ return self._state.state_vector() - def partial_trace(self, keep_qubits: Set['cirq.Qid']) -> np.ndarray: + def partial_trace(self, keep_qubits: Set[cirq.Qid]) -> np.ndarray: """Traces out all qubits except keep_qubits. Args: @@ -642,7 +641,7 @@ def to_numpy(self) -> np.ndarray: return self._state.to_numpy() def _act_on_fallback_( - self, action: Any, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True + self, action: Any, qubits: Sequence[cirq.Qid], allow_decompose: bool = True ) -> bool: """Delegates the action to self.apply_op""" return self._state.apply_op(action, self.get_axes(qubits), self.prng) diff --git a/cirq-core/cirq/contrib/routing/greedy.py b/cirq-core/cirq/contrib/routing/greedy.py index eda80fdaf02..4f1c5d30299 100644 --- a/cirq-core/cirq/contrib/routing/greedy.py +++ b/cirq-core/cirq/contrib/routing/greedy.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import itertools from typing import ( Callable, @@ -109,7 +111,7 @@ def __init__( op1.qubits ) & set(op2.qubits), - random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None, ): self.prng = value.parse_random_state(random_state) @@ -148,12 +150,12 @@ def get_edge_sets(self, edge_set_size: int) -> Iterable[Sequence[QidPair]]: ] return self.edge_sets[edge_set_size] - def log_to_phys(self, *qubits: 'cirq.Qid') -> Iterable[ops.Qid]: + def log_to_phys(self, *qubits: cirq.Qid) -> Iterable[ops.Qid]: """Returns an iterator over the physical qubits mapped to by the given logical qubits.""" return (self._log_to_phys[q] for q in qubits) - def phys_to_log(self, *qubits: 'cirq.Qid') -> Iterable[Optional[ops.Qid]]: + def phys_to_log(self, *qubits: cirq.Qid) -> Iterable[Optional[ops.Qid]]: """Returns an iterator over the logical qubits that map to the given physical qubits.""" return (self._phys_to_log[q] for q in qubits) diff --git a/cirq-core/cirq/contrib/routing/initialization.py b/cirq-core/cirq/contrib/routing/initialization.py index 9294cfc9f0e..efac1a716fd 100644 --- a/cirq-core/cirq/contrib/routing/initialization.py +++ b/cirq-core/cirq/contrib/routing/initialization.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import itertools from typing import cast, Dict, Hashable, TYPE_CHECKING @@ -32,7 +34,7 @@ def get_center(graph: nx.Graph) -> Hashable: def get_initial_mapping( logical_graph: nx.Graph, device_graph: nx.Graph, - random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, + random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None, ) -> Dict[ops.Qid, ops.Qid]: """Gets an initial mapping of logical to physical qubits for routing. diff --git a/cirq-core/cirq/contrib/routing/swap_network.py b/cirq-core/cirq/contrib/routing/swap_network.py index 7a2bc11b185..6c23f464723 100644 --- a/cirq-core/cirq/contrib/routing/swap_network.py +++ b/cirq-core/cirq/contrib/routing/swap_network.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Dict, Iterable, TYPE_CHECKING import cirq.contrib.acquaintance as cca @@ -35,20 +37,18 @@ class SwapNetwork: initial_mapping: The initial mapping from physical to logical qubits. """ - def __init__( - self, circuit: 'cirq.Circuit', initial_mapping: Dict['cirq.Qid', 'cirq.Qid'] - ) -> None: + def __init__(self, circuit: cirq.Circuit, initial_mapping: Dict[cirq.Qid, cirq.Qid]) -> None: if not all(isinstance(i, ops.Qid) for I in initial_mapping.items() for i in I): raise ValueError('Mapping must be from Qids to Qids.') self.circuit = circuit self.initial_mapping = initial_mapping - def final_mapping(self) -> Dict['cirq.Qid', 'cirq.Qid']: + def final_mapping(self) -> Dict[cirq.Qid, cirq.Qid]: mapping = dict(self.initial_mapping) cca.update_mapping(mapping, self.circuit.all_operations()) return mapping - def get_logical_operations(self) -> Iterable['cirq.Operation']: + def get_logical_operations(self) -> Iterable[cirq.Operation]: return cca.get_logical_operations(self.circuit.all_operations(), self.initial_mapping) def __eq__(self, other) -> bool: diff --git a/cirq-core/cirq/contrib/routing/utils.py b/cirq-core/cirq/contrib/routing/utils.py index 9401650515d..7c2777f6908 100644 --- a/cirq-core/cirq/contrib/routing/utils.py +++ b/cirq-core/cirq/contrib/routing/utils.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import operator import re from typing import Callable, Iterable, List, TYPE_CHECKING @@ -21,10 +23,10 @@ import cirq.contrib.acquaintance as cca from cirq import circuits, ops from cirq.contrib.circuitdag import CircuitDag -from cirq.contrib.routing.swap_network import SwapNetwork if TYPE_CHECKING: import cirq + from cirq.contrib.routing import SwapNetwork BINARY_OP_PREDICATE = Callable[[ops.Operation, ops.Operation], bool] @@ -86,7 +88,7 @@ def is_valid_routing( raise -def get_circuit_connectivity(circuit: 'cirq.Circuit') -> nx.Graph: +def get_circuit_connectivity(circuit: cirq.Circuit) -> nx.Graph: """Return a graph of all 2q interactions in a circuit. Nodes are qubits and undirected edges correspond to any two-qubit diff --git a/cirq-core/cirq/contrib/svg/svg.py b/cirq-core/cirq/contrib/svg/svg.py index d2322e7eea4..e2afc2d027c 100644 --- a/cirq-core/cirq/contrib/svg/svg.py +++ b/cirq-core/cirq/contrib/svg/svg.py @@ -1,4 +1,7 @@ # pylint: disable=wrong-or-nonexistent-copyright-notice + +from __future__ import annotations + from typing import cast, Dict, List, Tuple, TYPE_CHECKING import matplotlib.font_manager @@ -59,7 +62,7 @@ def _text(x: float, y: float, text: str, fontsize: int = 14): def _fit_horizontal( - tdd: 'cirq.TextDiagramDrawer', ref_boxwidth: float, col_padding: float + tdd: cirq.TextDiagramDrawer, ref_boxwidth: float, col_padding: float ) -> Tuple[List[float], List[float]]: """Figure out the horizontal spacing of columns to fit everything in. @@ -89,7 +92,7 @@ def _fit_horizontal( def _fit_vertical( - tdd: 'cirq.TextDiagramDrawer', ref_boxheight: float, row_padding: float + tdd: cirq.TextDiagramDrawer, ref_boxheight: float, row_padding: float ) -> Tuple[List[float], List[float], Dict[float, int]]: """Return data structures used to turn tdd vertical coordinates into well-spaced SVG coordinates. @@ -164,7 +167,7 @@ def _debug_spacing(col_starts, row_starts): # pragma: no cover def tdd_to_svg( - tdd: 'cirq.TextDiagramDrawer', + tdd: cirq.TextDiagramDrawer, ref_boxwidth: float = 40, ref_boxheight: float = 40, col_padding: float = 20, @@ -246,7 +249,7 @@ def tdd_to_svg( return t -def _validate_circuit(circuit: 'cirq.Circuit'): +def _validate_circuit(circuit: cirq.Circuit): if len(circuit) == 0: raise ValueError("Can't draw SVG diagram for empty circuits") @@ -260,14 +263,14 @@ class SVGCircuit: which will cause the circuit to be displayed as an SVG image. """ - def __init__(self, circuit: 'cirq.Circuit'): + def __init__(self, circuit: cirq.Circuit): self.circuit = circuit def _repr_svg_(self) -> str: return circuit_to_svg(self.circuit) -def circuit_to_svg(circuit: 'cirq.Circuit') -> str: +def circuit_to_svg(circuit: cirq.Circuit) -> str: """Render a circuit as SVG.""" _validate_circuit(circuit) tdd = circuit.to_text_diagram_drawer(transpose=False) diff --git a/cirq-core/cirq/devices/device.py b/cirq-core/cirq/devices/device.py index 3b6ae315904..224a8eb2d36 100644 --- a/cirq-core/cirq/devices/device.py +++ b/cirq-core/cirq/devices/device.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc from typing import FrozenSet, Iterable, Optional, TYPE_CHECKING @@ -57,7 +59,7 @@ class Device(metaclass=abc.ABCMeta): """ @property - def metadata(self) -> Optional['DeviceMetadata']: + def metadata(self) -> Optional[DeviceMetadata]: """Returns the associated Metadata with the device if applicable. Returns: @@ -65,7 +67,7 @@ def metadata(self) -> Optional['DeviceMetadata']: """ return None - def validate_operation(self, operation: 'cirq.Operation') -> None: + def validate_operation(self, operation: cirq.Operation) -> None: """Raises an exception if an operation is not valid. Args: @@ -75,7 +77,7 @@ def validate_operation(self, operation: 'cirq.Operation') -> None: ValueError: The operation isn't valid for this device. """ - def validate_circuit(self, circuit: 'cirq.AbstractCircuit') -> None: + def validate_circuit(self, circuit: cirq.AbstractCircuit) -> None: """Raises an exception if a circuit is not valid. Args: @@ -87,7 +89,7 @@ def validate_circuit(self, circuit: 'cirq.AbstractCircuit') -> None: for moment in circuit: self.validate_moment(moment) - def validate_moment(self, moment: 'cirq.Moment') -> None: + def validate_moment(self, moment: cirq.Moment) -> None: """Raises an exception if a moment is not valid. Args: @@ -104,7 +106,7 @@ def validate_moment(self, moment: 'cirq.Moment') -> None: class DeviceMetadata: """Parent type for all device specific metadata classes.""" - def __init__(self, qubits: Iterable['cirq.Qid'], nx_graph: 'nx.Graph'): + def __init__(self, qubits: Iterable[cirq.Qid], nx_graph: nx.Graph): """Construct a DeviceMetadata object. Args: @@ -114,11 +116,11 @@ def __init__(self, qubits: Iterable['cirq.Qid'], nx_graph: 'nx.Graph'): directional coupling, undirected edges indicate bi-directional coupling. """ - self._qubits_set: FrozenSet['cirq.Qid'] = frozenset(qubits) + self._qubits_set: FrozenSet[cirq.Qid] = frozenset(qubits) self._nx_graph = nx_graph @property - def qubit_set(self) -> FrozenSet['cirq.Qid']: + def qubit_set(self) -> FrozenSet[cirq.Qid]: """Returns the set of qubits on the device. Returns: @@ -127,7 +129,7 @@ def qubit_set(self) -> FrozenSet['cirq.Qid']: return self._qubits_set @property - def nx_graph(self) -> 'nx.Graph': + def nx_graph(self) -> nx.Graph: """Returns a nx.Graph where nodes are qubits and edges are couple-able qubits. Returns: @@ -150,6 +152,6 @@ def _json_dict_(self): return {'qubits': qubits_payload, 'nx_graph': graph_payload} @classmethod - def _from_json_dict_(cls, qubits: Iterable['cirq.Qid'], nx_graph: 'nx.Graph', **kwargs): + def _from_json_dict_(cls, qubits: Iterable[cirq.Qid], nx_graph: nx.Graph, **kwargs): graph_obj = nx.readwrite.json_graph.node_link_graph(nx_graph) return cls(qubits, graph_obj) diff --git a/cirq-core/cirq/devices/grid_device_metadata.py b/cirq-core/cirq/devices/grid_device_metadata.py index 6e8d3d4bf7a..0988bf22d0b 100644 --- a/cirq-core/cirq/devices/grid_device_metadata.py +++ b/cirq-core/cirq/devices/grid_device_metadata.py @@ -11,8 +11,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + """Metadata subtype for 2D Homogenous devices.""" +from __future__ import annotations + from typing import cast, FrozenSet, Iterable, Mapping, Optional, Tuple, TYPE_CHECKING import networkx as nx @@ -30,11 +33,11 @@ class GridDeviceMetadata(device.DeviceMetadata): def __init__( self, - qubit_pairs: Iterable[Tuple['cirq.GridQubit', 'cirq.GridQubit']], - gateset: 'cirq.Gateset', - gate_durations: Optional[Mapping['cirq.GateFamily', 'cirq.Duration']] = None, - all_qubits: Optional[Iterable['cirq.GridQubit']] = None, - compilation_target_gatesets: Iterable['cirq.CompilationTargetGateset'] = (), + qubit_pairs: Iterable[Tuple[cirq.GridQubit, cirq.GridQubit]], + gateset: cirq.Gateset, + gate_durations: Optional[Mapping[cirq.GateFamily, cirq.Duration]] = None, + all_qubits: Optional[Iterable[cirq.GridQubit]] = None, + compilation_target_gatesets: Iterable[cirq.CompilationTargetGateset] = (), ): """Create a GridDeviceMetadata object. @@ -115,7 +118,7 @@ def __init__( self._gate_durations = gate_durations @property - def qubit_set(self) -> FrozenSet['cirq.GridQubit']: + def qubit_set(self) -> FrozenSet[cirq.GridQubit]: """Returns the set of grid qubits on the device. Returns: @@ -124,7 +127,7 @@ def qubit_set(self) -> FrozenSet['cirq.GridQubit']: return cast(FrozenSet['cirq.GridQubit'], super().qubit_set) @property - def qubit_pairs(self) -> FrozenSet[FrozenSet['cirq.GridQubit']]: + def qubit_pairs(self) -> FrozenSet[FrozenSet[cirq.GridQubit]]: """Returns the set of all couple-able qubits on the device. Each element in the outer frozenset is a 2-element frozenset representing a bidirectional @@ -133,22 +136,22 @@ def qubit_pairs(self) -> FrozenSet[FrozenSet['cirq.GridQubit']]: return self._qubit_pairs @property - def isolated_qubits(self) -> FrozenSet['cirq.GridQubit']: + def isolated_qubits(self) -> FrozenSet[cirq.GridQubit]: """Returns the set of all isolated qubits on the device (if applicable).""" return self._isolated_qubits @property - def gateset(self) -> 'cirq.Gateset': + def gateset(self) -> cirq.Gateset: """Returns the `cirq.Gateset` of supported gates on this device.""" return self._gateset @property - def compilation_target_gatesets(self) -> Tuple['cirq.CompilationTargetGateset', ...]: + def compilation_target_gatesets(self) -> Tuple[cirq.CompilationTargetGateset, ...]: """Returns a sequence of valid `cirq.CompilationTargetGateset`s for this device.""" return self._compilation_target_gatesets @property - def gate_durations(self) -> Optional[Mapping['cirq.GateFamily', 'cirq.Duration']]: + def gate_durations(self) -> Optional[Mapping[cirq.GateFamily, cirq.Duration]]: """Get a dictionary mapping from gate family to duration for gates. To look up the duration of a specific gate instance / gate type / operation which is part of diff --git a/cirq-core/cirq/devices/grid_qubit.py b/cirq-core/cirq/devices/grid_qubit.py index b50b3ca1b95..fb8879d7818 100644 --- a/cirq-core/cirq/devices/grid_qubit.py +++ b/cirq-core/cirq/devices/grid_qubit.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc import functools import weakref @@ -104,17 +106,17 @@ def col(self) -> int: def dimension(self) -> int: return self._dimension - def with_dimension(self, dimension: int) -> 'GridQid': + def with_dimension(self, dimension: int) -> GridQid: return GridQid(self._row, self._col, dimension=dimension) - def is_adjacent(self, other: 'cirq.Qid') -> bool: + def is_adjacent(self, other: cirq.Qid) -> bool: """Determines if two qubits are adjacent qubits.""" return ( isinstance(other, GridQubit) and abs(self._row - other._row) + abs(self._col - other._col) == 1 ) - def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set['_BaseGridQid']: + def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set[_BaseGridQid]: """Returns qubits that are potential neighbors to this GridQid Args: @@ -204,7 +206,7 @@ class GridQid(_BaseGridQid): # Holds weak references so instances can still be garbage collected. _cache = weakref.WeakValueDictionary[Tuple[int, int, int], 'cirq.GridQid']() - def __new__(cls, row: int, col: int, *, dimension: int) -> 'cirq.GridQid': + def __new__(cls, row: int, col: int, *, dimension: int) -> cirq.GridQid: """Creates a grid qid at the given row, col coordinate Args: @@ -234,11 +236,11 @@ def __getnewargs_ex__(self): def __getstate__(self) -> Dict[str, Any]: return {} - def _with_row_col(self, row: int, col: int) -> 'GridQid': + def _with_row_col(self, row: int, col: int) -> GridQid: return GridQid(row, col, dimension=self._dimension) @staticmethod - def square(diameter: int, top: int = 0, left: int = 0, *, dimension: int) -> List['GridQid']: + def square(diameter: int, top: int = 0, left: int = 0, *, dimension: int) -> List[GridQid]: """Returns a square of GridQid. Args: @@ -254,9 +256,7 @@ def square(diameter: int, top: int = 0, left: int = 0, *, dimension: int) -> Lis return GridQid.rect(diameter, diameter, top=top, left=left, dimension=dimension) @staticmethod - def rect( - rows: int, cols: int, top: int = 0, left: int = 0, *, dimension: int - ) -> List['GridQid']: + def rect(rows: int, cols: int, top: int = 0, left: int = 0, *, dimension: int) -> List[GridQid]: """Returns a rectangle of GridQid. Args: @@ -277,7 +277,7 @@ def rect( ] @staticmethod - def from_diagram(diagram: str, dimension: int) -> List['GridQid']: + def from_diagram(diagram: str, dimension: int) -> List[GridQid]: """Parse ASCII art device layout into a device. As an example, the below diagram will create a list of GridQid in a @@ -337,9 +337,7 @@ def __repr__(self) -> str: def __str__(self) -> str: return f"q({self._row}, {self._col}) (d={self._dimension})" - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: return protocols.CircuitDiagramInfo( wire_symbols=(f"({self._row}, {self._col}) (d={self._dimension})",) ) @@ -371,7 +369,7 @@ class GridQubit(_BaseGridQid): # Holds weak references so instances can still be garbage collected. _cache = weakref.WeakValueDictionary[Tuple[int, int], 'cirq.GridQubit']() - def __new__(cls, row: int, col: int) -> 'cirq.GridQubit': + def __new__(cls, row: int, col: int) -> cirq.GridQubit: """Creates a grid qubit at the given row, col coordinate Args: @@ -396,11 +394,11 @@ def __getnewargs__(self): def __getstate__(self) -> Dict[str, Any]: return {} - def _with_row_col(self, row: int, col: int) -> 'GridQubit': + def _with_row_col(self, row: int, col: int) -> GridQubit: return GridQubit(row, col) @staticmethod - def square(diameter: int, top: int = 0, left: int = 0) -> List['GridQubit']: + def square(diameter: int, top: int = 0, left: int = 0) -> List[GridQubit]: """Returns a square of GridQubits. Args: @@ -414,7 +412,7 @@ def square(diameter: int, top: int = 0, left: int = 0) -> List['GridQubit']: return GridQubit.rect(diameter, diameter, top=top, left=left) @staticmethod - def rect(rows: int, cols: int, top: int = 0, left: int = 0) -> List['GridQubit']: + def rect(rows: int, cols: int, top: int = 0, left: int = 0) -> List[GridQubit]: """Returns a rectangle of GridQubits. Args: @@ -433,7 +431,7 @@ def rect(rows: int, cols: int, top: int = 0, left: int = 0) -> List['GridQubit'] ] @staticmethod - def from_diagram(diagram: str) -> List['GridQubit']: + def from_diagram(diagram: str) -> List[GridQubit]: """Parse ASCII art into device layout info. As an example, the below diagram will create a list of @@ -490,9 +488,7 @@ def __repr__(self) -> str: def __str__(self) -> str: return f"q({self._row}, {self._col})" - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: return protocols.CircuitDiagramInfo(wire_symbols=(f"({self._row}, {self._col})",)) def _json_dict_(self) -> Dict[str, Any]: diff --git a/cirq-core/cirq/devices/grid_qubit_test.py b/cirq-core/cirq/devices/grid_qubit_test.py index 3c49f8d65ad..696dd517fb5 100644 --- a/cirq-core/cirq/devices/grid_qubit_test.py +++ b/cirq-core/cirq/devices/grid_qubit_test.py @@ -58,7 +58,7 @@ def test_grid_qid_pickled_hash(): _test_qid_pickled_hash(q, q_bad) -def _test_qid_pickled_hash(q: 'cirq.Qid', q_bad: 'cirq.Qid') -> None: +def _test_qid_pickled_hash(q: cirq.Qid, q_bad: cirq.Qid) -> None: """Test that hashes are not pickled with Qid instances.""" assert q_bad is not q _ = hash(q_bad) # compute hash to ensure it is cached. diff --git a/cirq-core/cirq/devices/insertion_noise_model.py b/cirq-core/cirq/devices/insertion_noise_model.py index ad9c7b3aa75..9fe9f5db364 100644 --- a/cirq-core/cirq/devices/insertion_noise_model.py +++ b/cirq-core/cirq/devices/insertion_noise_model.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import dataclasses from typing import Any, Dict, List, Optional, Sequence, TYPE_CHECKING @@ -42,16 +44,14 @@ class InsertionNoiseModel(devices.NoiseModel): with PHYSICAL_GATE_TAG. """ - ops_added: Dict[noise_utils.OpIdentifier, 'cirq.Operation'] = dataclasses.field( + ops_added: Dict[noise_utils.OpIdentifier, cirq.Operation] = dataclasses.field( default_factory=dict ) prepend: bool = False require_physical_tag: bool = True - def noisy_moment( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': - noise_ops: List['cirq.Operation'] = [] + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE: + noise_ops: List[cirq.Operation] = [] candidate_ops = [ op for op in moment diff --git a/cirq-core/cirq/devices/line_qubit.py b/cirq-core/cirq/devices/line_qubit.py index b17d6f55816..ff02f092776 100644 --- a/cirq-core/cirq/devices/line_qubit.py +++ b/cirq-core/cirq/devices/line_qubit.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc import functools import weakref @@ -93,10 +95,10 @@ def x(self) -> int: def dimension(self) -> int: return self._dimension - def with_dimension(self, dimension: int) -> 'LineQid': + def with_dimension(self, dimension: int) -> LineQid: return LineQid(self._x, dimension) - def is_adjacent(self, other: 'cirq.Qid') -> bool: + def is_adjacent(self, other: cirq.Qid) -> bool: """Determines if two qubits are adjacent line qubits. Args: @@ -106,7 +108,7 @@ def is_adjacent(self, other: 'cirq.Qid') -> bool: """ return isinstance(other, _BaseLineQid) and abs(self._x - other._x) == 1 - def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set['_BaseLineQid']: + def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set[_BaseLineQid]: """Returns qubits that are potential neighbors to this LineQubit Args: @@ -184,7 +186,7 @@ class LineQid(_BaseLineQid): # Holds weak references so instances can still be garbage collected. _cache = weakref.WeakValueDictionary[Tuple[int, int], 'cirq.LineQid']() - def __new__(cls, x: int, dimension: int) -> 'cirq.LineQid': + def __new__(cls, x: int, dimension: int) -> cirq.LineQid: """Initializes a line qid at the given x coordinate. Args: @@ -212,11 +214,11 @@ def __getnewargs__(self): def __getstate__(self) -> Dict[str, Any]: return {} - def _with_x(self, x: int) -> 'LineQid': + def _with_x(self, x: int) -> LineQid: return LineQid(x, dimension=self._dimension) @staticmethod - def range(*range_args, dimension: int) -> List['LineQid']: + def range(*range_args, dimension: int) -> List[LineQid]: """Returns a range of line qids. Args: @@ -230,7 +232,7 @@ def range(*range_args, dimension: int) -> List['LineQid']: return [LineQid(i, dimension=dimension) for i in range(*range_args)] @staticmethod - def for_qid_shape(qid_shape: Sequence[int], start: int = 0, step: int = 1) -> List['LineQid']: + def for_qid_shape(qid_shape: Sequence[int], start: int = 0, step: int = 1) -> List[LineQid]: """Returns a range of line qids for each entry in `qid_shape` with matching dimension. @@ -244,7 +246,7 @@ def for_qid_shape(qid_shape: Sequence[int], start: int = 0, step: int = 1) -> Li ] @staticmethod - def for_gate(val: Any, start: int = 0, step: int = 1) -> List['LineQid']: + def for_gate(val: Any, start: int = 0, step: int = 1) -> List[LineQid]: """Returns a range of line qids with the same qid shape as the gate. Args: @@ -264,9 +266,7 @@ def __repr__(self) -> str: def __str__(self) -> str: return f"q({self._x}) (d={self._dimension})" - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x} (d={self._dimension})",)) def _json_dict_(self) -> Dict[str, Any]: @@ -296,7 +296,7 @@ class LineQubit(_BaseLineQid): # Holds weak references so instances can still be garbage collected. _cache = weakref.WeakValueDictionary[int, 'cirq.LineQubit']() - def __new__(cls, x: int) -> 'cirq.LineQubit': + def __new__(cls, x: int) -> cirq.LineQubit: """Initializes a line qid at the given x coordinate. Args: @@ -318,11 +318,11 @@ def __getnewargs__(self): def __getstate__(self) -> Dict[str, Any]: return {} - def _with_x(self, x: int) -> 'LineQubit': + def _with_x(self, x: int) -> LineQubit: return LineQubit(x) @staticmethod - def range(*range_args) -> List['LineQubit']: + def range(*range_args) -> List[LineQubit]: """Returns a range of line qubits. Args: @@ -339,9 +339,7 @@ def __repr__(self) -> str: def __str__(self) -> str: return f"q({self._x})" - def _circuit_diagram_info_( - self, args: 'cirq.CircuitDiagramInfoArgs' - ) -> 'cirq.CircuitDiagramInfo': + def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo: return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x}",)) def _json_dict_(self) -> Dict[str, Any]: diff --git a/cirq-core/cirq/devices/named_topologies.py b/cirq-core/cirq/devices/named_topologies.py index 7ae566d465b..5393dd2e7d7 100644 --- a/cirq-core/cirq/devices/named_topologies.py +++ b/cirq-core/cirq/devices/named_topologies.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + import abc import warnings from dataclasses import dataclass @@ -127,7 +129,7 @@ def __post_init__(self): ) object.__setattr__(self, 'graph', graph) - def nodes_as_linequbits(self) -> List['cirq.LineQubit']: + def nodes_as_linequbits(self) -> List[cirq.LineQubit]: """Get the graph nodes as cirq.LineQubit""" return [LineQubit(x) for x in sorted(self.graph.nodes)] @@ -142,7 +144,7 @@ def draw(self, ax=None, tilted: bool = True, **kwargs) -> Dict[Any, Tuple[int, i g2 = nx.relabel_nodes(self.graph, {n: (n, 1) for n in self.graph.nodes}) return draw_gridlike(g2, ax=ax, tilted=tilted, **kwargs) - def nodes_to_linequbits(self, offset: int = 0) -> Dict[int, 'cirq.LineQubit']: + def nodes_to_linequbits(self, offset: int = 0) -> Dict[int, cirq.LineQubit]: """Return a mapping from graph nodes to `cirq.LineQubit` Args: @@ -240,11 +242,11 @@ def draw(self, ax=None, tilted=True, **kwargs): """ return draw_gridlike(self.graph, ax=ax, tilted=tilted, **kwargs) - def nodes_as_gridqubits(self) -> List['cirq.GridQubit']: + def nodes_as_gridqubits(self) -> List[cirq.GridQubit]: """Get the graph nodes as cirq.GridQubit""" return [GridQubit(r, c) for r, c in sorted(self.graph.nodes)] - def nodes_to_gridqubits(self, offset=(0, 0)) -> Dict[Tuple[int, int], 'cirq.GridQubit']: + def nodes_to_gridqubits(self, offset=(0, 0)) -> Dict[Tuple[int, int], cirq.GridQubit]: """Return a mapping from graph nodes to `cirq.GridQubit` Args: diff --git a/cirq-core/cirq/devices/noise_model.py b/cirq-core/cirq/devices/noise_model.py index fe8dc94a374..e071fcc806b 100644 --- a/cirq-core/cirq/devices/noise_model.py +++ b/cirq-core/cirq/devices/noise_model.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Any, Callable, Dict, Iterable, Sequence, TYPE_CHECKING, Union from cirq import ops, protocols, value @@ -41,7 +43,7 @@ class NoiseModel(metaclass=value.ABCMetaImplementAnyOneOf): """ @classmethod - def from_noise_model_like(cls, noise: 'cirq.NOISE_MODEL_LIKE') -> 'cirq.NoiseModel': + def from_noise_model_like(cls, noise: cirq.NOISE_MODEL_LIKE) -> cirq.NoiseModel: """Transforms an object into a noise model if unambiguously possible. Args: @@ -76,7 +78,7 @@ def from_noise_model_like(cls, noise: 'cirq.NOISE_MODEL_LIKE') -> 'cirq.NoiseMod f'or a single qubit gate). Got {noise!r}' ) - def is_virtual_moment(self, moment: 'cirq.Moment') -> bool: + def is_virtual_moment(self, moment: cirq.Moment) -> bool: """Returns true iff the given moment is non-empty and all of its operations are virtual. @@ -95,16 +97,16 @@ def is_virtual_moment(self, moment: 'cirq.Moment') -> bool: return all(ops.VirtualTag() in op.tags for op in moment) def _noisy_moments_impl_moment( - self, moments: Iterable['cirq.Moment'], system_qubits: Sequence['cirq.Qid'] - ) -> Sequence['cirq.OP_TREE']: + self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid] + ) -> Sequence[cirq.OP_TREE]: result = [] for moment in moments: result.append(self.noisy_moment(moment, system_qubits)) return result def _noisy_moments_impl_operation( - self, moments: Iterable['cirq.Moment'], system_qubits: Sequence['cirq.Qid'] - ) -> Sequence['cirq.OP_TREE']: + self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid] + ) -> Sequence[cirq.OP_TREE]: result = [] for moment in moments: result.append([self.noisy_operation(op) for op in moment]) @@ -113,8 +115,8 @@ def _noisy_moments_impl_operation( @value.alternative(requires='noisy_moment', implementation=_noisy_moments_impl_moment) @value.alternative(requires='noisy_operation', implementation=_noisy_moments_impl_operation) def noisy_moments( - self, moments: Iterable['cirq.Moment'], system_qubits: Sequence['cirq.Qid'] - ) -> Sequence['cirq.OP_TREE']: + self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid] + ) -> Sequence[cirq.OP_TREE]: """Adds possibly stateful noise to a series of moments. Args: @@ -128,20 +130,18 @@ def noisy_moments( raise NotImplementedError def _noisy_moment_impl_moments( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': + self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid] + ) -> cirq.OP_TREE: return self.noisy_moments([moment], system_qubits) def _noisy_moment_impl_operation( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': + self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid] + ) -> cirq.OP_TREE: return [self.noisy_operation(op) for op in moment] @value.alternative(requires='noisy_moments', implementation=_noisy_moment_impl_moments) @value.alternative(requires='noisy_operation', implementation=_noisy_moment_impl_operation) - def noisy_moment( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE: """Adds noise to the operations from a moment. Args: @@ -153,15 +153,15 @@ def noisy_moment( """ raise NotImplementedError - def _noisy_operation_impl_moments(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE': + def _noisy_operation_impl_moments(self, operation: cirq.Operation) -> cirq.OP_TREE: return self.noisy_moments([moment_module.Moment([operation])], operation.qubits) - def _noisy_operation_impl_moment(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE': + def _noisy_operation_impl_moment(self, operation: cirq.Operation) -> cirq.OP_TREE: return self.noisy_moment(moment_module.Moment([operation]), operation.qubits) @value.alternative(requires='noisy_moments', implementation=_noisy_operation_impl_moments) @value.alternative(requires='noisy_moment', implementation=_noisy_operation_impl_moment) - def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE': + def noisy_operation(self, operation: cirq.Operation) -> cirq.OP_TREE: """Adds noise to an individual operation. Args: @@ -178,15 +178,13 @@ def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE': class _NoNoiseModel(NoiseModel): """A default noise model that adds no noise.""" - def noisy_moments(self, moments: Iterable['cirq.Moment'], system_qubits: Sequence['cirq.Qid']): + def noisy_moments(self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]): return list(moments) - def noisy_moment( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.Moment': + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]) -> cirq.Moment: return moment - def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.Operation': + def noisy_operation(self, operation: cirq.Operation) -> cirq.Operation: return operation def _value_equality_values_(self) -> Any: @@ -216,7 +214,7 @@ class ConstantQubitNoiseModel(NoiseModel): operation is given as "the noise to use" for a `NOISE_MODEL_LIKE` parameter. """ - def __init__(self, qubit_noise_gate: 'cirq.Gate', prepend: bool = False): + def __init__(self, qubit_noise_gate: cirq.Gate, prepend: bool = False): """Noise model which applies a specific gate as noise to all gates. Args: @@ -237,7 +235,7 @@ def _value_equality_values_(self) -> Any: def __repr__(self) -> str: return f'cirq.ConstantQubitNoiseModel({self.qubit_noise_gate!r})' - def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']): + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]): # Noise should not be appended to previously-added noise. if self.is_virtual_moment(moment): return moment @@ -260,7 +258,7 @@ def _has_mixture_(self) -> bool: class GateSubstitutionNoiseModel(NoiseModel): - def __init__(self, substitution_func: Callable[['cirq.Operation'], 'cirq.Operation']): + def __init__(self, substitution_func: Callable[[cirq.Operation], cirq.Operation]): """Noise model which replaces operations using a substitution function. Args: @@ -268,13 +266,11 @@ def __init__(self, substitution_func: Callable[['cirq.Operation'], 'cirq.Operati """ self.substitution_func = substitution_func - def noisy_moment( - self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid'] - ) -> 'cirq.OP_TREE': + def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE: return moment_module.Moment([self.substitution_func(op) for op in moment.operations]) -NO_NOISE: 'cirq.NoiseModel' = _NoNoiseModel() +NO_NOISE: cirq.NoiseModel = _NoNoiseModel() document( NO_NOISE, """The trivial noise model with no effects. @@ -298,7 +294,7 @@ def noisy_moment( ) -def validate_all_measurements(moment: 'cirq.Moment') -> bool: +def validate_all_measurements(moment: cirq.Moment) -> bool: """Ensures that the moment is homogenous and returns whether all ops are measurement gates. Args: