def map_moments( circuit: CIRCUIT_TYPE, map_func: Callable[[circuits.Moment, int], Union[circuits.Moment, Sequence[circuits.Moment]]], *, deep: bool = False, ) -> CIRCUIT_TYPE: """Applies local transformation on moments, by calling `map_func(moment)` for each moment. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. map_func: Mapping function from (cirq.Moment, moment_index) to a sequence of moments. deep: If true, `map_func` will be recursively applied to circuits wrapped inside any circuit operations contained within `circuit`. Returns: Copy of input circuit with mapped moments. """ mutable_circuit = circuit.unfreeze(copy=False) if deep: batch_replace = [] for i, op in circuit.findall_operations( lambda o: isinstance(o.untagged, circuits.CircuitOperation)): op_untagged = cast(circuits.CircuitOperation, op.untagged) mapped_op = op_untagged.replace(circuit=map_moments( op_untagged.mapped_circuit(), map_func, deep=deep).freeze()) batch_replace.append((i, op, mapped_op)) mutable_circuit = circuit.unfreeze(copy=True) mutable_circuit.batch_replace(batch_replace) return _create_target_circuit_type( (map_func(mutable_circuit[i], i) for i in range(len(mutable_circuit))), circuit)
def unroll_circuit_op_greedy_frontier( circuit: CIRCUIT_TYPE, *, tags_to_check=(MAPPED_CIRCUIT_OP_TAG, )) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations inline at qubit frontier. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `circuit.insert_at_frontier` method. The greedy approach attempts to reuse any available space in existing moments on the right of circuit_op before inserting new moments. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded inline at qubit frontier. """ unrolled_circuit = circuit.unfreeze(copy=True) frontier: Dict['cirq.Qid', int] = defaultdict(lambda: 0) for idx, op in circuit.findall_operations( lambda op: _check_circuit_op(op, tags_to_check)): idx = max(idx, max(frontier[q] for q in op.qubits)) unrolled_circuit.clear_operations_touching(op.qubits, [idx]) frontier = unrolled_circuit.insert_at_frontier( protocols.decompose_once(op), idx, frontier) return _to_target_circuit_type(unrolled_circuit, circuit)
def unroll_circuit_op_greedy_earliest( circuit: CIRCUIT_TYPE, *, tags_to_check=(MAPPED_CIRCUIT_OP_TAG, )) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations using EARLIEST strategy. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `cirq.InsertStrategy.EARLIEST` strategy. The greedy approach attempts to minimize circuit depth of the resulting circuit. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded using EARLIEST strategy. """ batch_removals = [ *circuit.findall_operations( lambda op: _check_circuit_op(op, tags_to_check)) ] batch_inserts = [(i, protocols.decompose_once(op)) for i, op in batch_removals] unrolled_circuit = circuit.unfreeze(copy=True) unrolled_circuit.batch_remove(batch_removals) unrolled_circuit.batch_insert(batch_inserts) return _to_target_circuit_type(unrolled_circuit, circuit)
def map_moments( circuit: CIRCUIT_TYPE, map_func: Callable[[circuits.Moment, int], Union[circuits.Moment, Sequence[circuits.Moment]]], *, tags_to_ignore: Sequence[Hashable] = (), deep: bool = False, ) -> CIRCUIT_TYPE: """Applies local transformation on moments, by calling `map_func(moment)` for each moment. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. map_func: Mapping function from (cirq.Moment, moment_index) to a sequence of moments. tags_to_ignore: Tagged circuit operations marked with any of `tags_to_ignore` will be ignored when recursively applying the transformer primitive to sub-circuits, given deep=True. deep: If true, `map_func` will be recursively applied to circuits wrapped inside any circuit operations contained within `circuit`. Returns: Copy of input circuit with mapped moments. """ mutable_circuit = circuit.unfreeze(copy=False) if deep: batch_replace = [] for i, op in circuit.findall_operations( lambda o: isinstance(o.untagged, circuits.CircuitOperation)): if set(op.tags).intersection(tags_to_ignore): continue op_untagged = cast(circuits.CircuitOperation, op.untagged) mapped_op = op_untagged.replace( circuit=map_moments(op_untagged.circuit, map_func, tags_to_ignore=tags_to_ignore, deep=deep)).with_tags(*op.tags) batch_replace.append((i, op, mapped_op)) mutable_circuit = circuit.unfreeze(copy=True) mutable_circuit.batch_replace(batch_replace) return _create_target_circuit_type( (map_func(mutable_circuit[i], i) for i in range(len(mutable_circuit))), circuit)
def unroll_circuit_op_greedy_frontier( circuit: CIRCUIT_TYPE, *, deep: bool = False, tags_to_check: Optional[Sequence[Hashable]] = (MAPPED_CIRCUIT_OP_TAG, ), ) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations inline at qubit frontier. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `circuit.insert_at_frontier` method. The greedy approach attempts to reuse any available space in existing moments on the right of circuit_op before inserting new moments. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. deep: If true, the transformer primitive will be recursively applied to all circuits wrapped inside circuit operations. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded inline at qubit frontier. """ unrolled_circuit = circuit.unfreeze(copy=True) frontier: Dict['cirq.Qid', int] = defaultdict(lambda: 0) idx = 0 while idx < len(unrolled_circuit): for op in unrolled_circuit[idx].operations: # Don't touch stuff inserted by unrolling previous circuit ops. if not isinstance(op.untagged, circuits.CircuitOperation): continue if any(frontier[q] > idx for q in op.qubits): continue op_untagged = cast(circuits.CircuitOperation, op.untagged) if deep: op_untagged = op_untagged.replace( circuit=unroll_circuit_op_greedy_frontier( op_untagged.circuit, deep=deep, tags_to_check=tags_to_check)) if tags_to_check is None or set(tags_to_check).intersection( op.tags): unrolled_circuit.clear_operations_touching(op.qubits, [idx]) frontier = unrolled_circuit.insert_at_frontier( op_untagged.mapped_circuit().all_operations(), idx, frontier) elif deep: unrolled_circuit.batch_replace([ (idx, op, op_untagged.with_tags(*op.tags)) ]) idx += 1 return _to_target_circuit_type(unrolled_circuit, circuit)
def unroll_circuit_op_greedy_earliest( circuit: CIRCUIT_TYPE, *, deep: bool = False, tags_to_check: Optional[Sequence[Hashable]] = (MAPPED_CIRCUIT_OP_TAG, ), ) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations using EARLIEST strategy. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `cirq.InsertStrategy.EARLIEST` strategy. The greedy approach attempts to minimize circuit depth of the resulting circuit. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. deep: If true, the transformer primitive will be recursively applied to all circuits wrapped inside circuit operations. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded using EARLIEST strategy. """ batch_replace = [] batch_remove = [] batch_insert = [] for i, op in circuit.findall_operations( lambda o: isinstance(o.untagged, circuits.CircuitOperation)): op_untagged = cast(circuits.CircuitOperation, op.untagged) if deep: op_untagged = op_untagged.replace( circuit=unroll_circuit_op_greedy_earliest( op_untagged.circuit, deep=deep, tags_to_check=tags_to_check)) if tags_to_check is None or set(tags_to_check).intersection(op.tags): batch_remove.append((i, op)) batch_insert.append( (i, op_untagged.mapped_circuit().all_operations())) elif deep: batch_replace.append((i, op, op_untagged.with_tags(*op.tags))) unrolled_circuit = circuit.unfreeze(copy=True) unrolled_circuit.batch_replace(batch_replace) unrolled_circuit.batch_remove(batch_remove) unrolled_circuit.batch_insert(batch_insert) return _to_target_circuit_type(unrolled_circuit, circuit)
def unroll_circuit_op_greedy_earliest( circuit: CIRCUIT_TYPE, *, deep: bool = False, tags_to_check: Optional[Sequence[Hashable]] = (MAPPED_CIRCUIT_OP_TAG, ), ) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations using EARLIEST strategy. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `cirq.InsertStrategy.EARLIEST` strategy. The greedy approach attempts to minimize circuit depth of the resulting circuit. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. deep: If True, `unroll_circuit_op_greedy_earliest` is recursively called on all circuit operations matching `tags_to_check`. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded using EARLIEST strategy. """ batch_removals = [ *circuit.findall_operations( lambda op: _check_circuit_op(op, tags_to_check)) ] batch_inserts = [] for i, op in batch_removals: sub_circuit = cast(circuits.CircuitOperation, op.untagged).mapped_circuit() sub_circuit = (unroll_circuit_op_greedy_earliest( sub_circuit, deep=deep, tags_to_check=tags_to_check) if deep else sub_circuit) batch_inserts += [(i, sub_circuit.all_operations())] unrolled_circuit = circuit.unfreeze(copy=True) unrolled_circuit.batch_remove(batch_removals) unrolled_circuit.batch_insert(batch_inserts) return _to_target_circuit_type(unrolled_circuit, circuit)
def unroll_circuit_op_greedy_frontier( circuit: CIRCUIT_TYPE, *, deep: bool = False, tags_to_check: Optional[Sequence[Hashable]] = (MAPPED_CIRCUIT_OP_TAG, ), ) -> CIRCUIT_TYPE: """Unrolls (tagged) `cirq.CircuitOperation`s by inserting operations inline at qubit frontier. Each matching `cirq.CircuitOperation` is replaced by inserting underlying operations using the `circuit.insert_at_frontier` method. The greedy approach attempts to reuse any available space in existing moments on the right of circuit_op before inserting new moments. Args: circuit: Input circuit to apply the transformations on. The input circuit is not mutated. deep: If True, `unroll_circuit_op_greedy_frontier` is recursively called on all circuit operations matching `tags_to_check`. tags_to_check: If specified, only circuit operations tagged with one of the `tags_to_check` are unrolled. Returns: Copy of input circuit with (Tagged) CircuitOperation's expanded inline at qubit frontier. """ unrolled_circuit = circuit.unfreeze(copy=True) frontier: Dict['cirq.Qid', int] = defaultdict(lambda: 0) for idx, op in circuit.findall_operations( lambda op: _check_circuit_op(op, tags_to_check)): idx = max(idx, max(frontier[q] for q in op.qubits)) unrolled_circuit.clear_operations_touching(op.qubits, [idx]) sub_circuit = cast(circuits.CircuitOperation, op.untagged).mapped_circuit() sub_circuit = (unroll_circuit_op_greedy_earliest( sub_circuit, deep=deep, tags_to_check=tags_to_check) if deep else sub_circuit) frontier = unrolled_circuit.insert_at_frontier( sub_circuit.all_operations(), idx, frontier) return _to_target_circuit_type(unrolled_circuit, circuit)