def complete_acquaintance_strategy( 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: qubit_order: The qubits on which the strategy should be defined. acquaintance_size: The maximum number of qubits to be acted on by an operation. swap_gate: The gate used to swap logical indices. Returns: A circuit capable of implementing any set of k-local operations. Raises: ValueError: If `acquaintance_size` is negative. """ if acquaintance_size < 0: raise ValueError('acquaintance_size must be non-negative.') if acquaintance_size == 0: return circuits.Circuit() if acquaintance_size > len(qubit_order): return circuits.Circuit() if acquaintance_size == len(qubit_order): return circuits.Circuit(acquaint(*qubit_order)) strategy = circuits.Circuit((acquaint(q) for q in qubit_order)) for size_to_acquaint in range(2, acquaintance_size + 1): expose_acquaintance_gates(strategy) replace_acquaintance_with_swap_network(strategy, qubit_order, size_to_acquaint, swap_gate) return strategy
def complete_acquaintance_strategy(qubit_order: Sequence[ops.Qid], acquaintance_size: int=0, ) -> circuits.Circuit: """ Returns an acquaintance strategy capable of executing a gate corresponding to any set of at most acquaintance_size qubits. Args: qubit_order: The qubits on which the strategy should be defined. acquaintance_size: The maximum number of qubits to be acted on by an operation. Returns: An circuit capable of implementing any set of k-local operation. """ if acquaintance_size < 0: raise ValueError('acquaintance_size must be non-negative.') elif acquaintance_size == 0: return circuits.Circuit(device=UnconstrainedAcquaintanceDevice) if acquaintance_size > len(qubit_order): return circuits.Circuit(device=UnconstrainedAcquaintanceDevice) if acquaintance_size == len(qubit_order): return circuits.Circuit.from_ops( acquaint(*qubit_order), device=UnconstrainedAcquaintanceDevice) strategy = circuits.Circuit.from_ops( (acquaint(q) for q in qubit_order), device=UnconstrainedAcquaintanceDevice) for size_to_acquaint in range(2, acquaintance_size + 1): expose_acquaintance_gates(strategy) replace_acquaintance_with_swap_network( strategy, qubit_order, size_to_acquaint) return strategy
def decompose_complete(self, qubits: Sequence[ops.Qid]) -> ops.OP_TREE: swap_gate = SwapPermutationGate(self.swap_gate) if self.part_size == 1: yield acquaint(*qubits) return for k in range(-self.part_size + 1, self.part_size - 1): for x in range(abs(k), 2 * self.part_size - abs(k), 2): yield acquaint(*qubits[x:x + 2]) yield swap_gate(*qubits[x:x + 2]) yield acquaint(qubits[self.part_size - 1], qubits[self.part_size]) for k in reversed(range(-self.part_size + 1, self.part_size - 1)): for x in range(abs(k), 2 * self.part_size - abs(k), 2): yield acquaint(*qubits[x:x + 2]) yield swap_gate(*qubits[x:x + 2])
def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': part_lens = list( itertools.chain(*(self.part_lens[side] for side in ('left', 'right')))) n_qubits = 0 parts = [] for part_len in part_lens: parts.append(list(qubits[n_qubits:n_qubits + part_len])) n_qubits += part_len n_parts = len(part_lens) n_left_parts = len(self.part_lens['left']) n_right_parts = n_parts - n_left_parts mins = itertools.chain(range(n_left_parts - 1, 0, -1), range(n_right_parts)) maxs = itertools.chain(range(n_left_parts, n_parts), range(n_parts - 1, n_right_parts, -1)) SHIFT = functools.partial(CircularShiftGate, swap_gate=self.swap_gate) for i, j in zip(mins, maxs): for k in range(i, j, 2): left_part, right_part = parts[k:k + 2] parts_qubits = left_part + right_part yield acquaint(*parts_qubits) yield SHIFT(len(parts_qubits), len(left_part))(*parts_qubits) parts[k] = parts_qubits[:len(right_part)] parts[k + 1] = parts_qubits[len(right_part):]
def remove_redundant_acquaintance_opportunities( strategy: circuits.Circuit) -> None: """Removes redundant acquaintance opportunities.""" if not is_acquaintance_strategy(strategy): raise TypeError('not is_acquaintance_strategy(circuit)') qubits = tuple(strategy.all_qubits()) mapping = {q: i for i, q in enumerate(qubits)} expose_acquaintance_gates(strategy) annotated_strategy = strategy.copy() LogicalAnnotator(mapping)(annotated_strategy) new_moments = [] # type: List[ops.Moment] acquaintance_opps = set() # type: Set[FrozenSet[int]] for moment in annotated_strategy: new_moment = [] # type: List[ops.Operation] for op in moment: if isinstance(op, AcquaintanceOperation): opp = frozenset(cast(Sequence[int], op.logical_indices)) if opp not in acquaintance_opps: acquaintance_opps.add(opp) new_moment.append(acquaint(*op.qubits)) else: new_moment.append(op) new_moments.append(ops.Moment(new_moment)) strategy._moments = new_moments
def remove_redundant_acquaintance_opportunities(strategy: 'cirq.Circuit') -> int: """Removes redundant acquaintance opportunities.""" qubits = sorted(strategy.all_qubits()) mapping = {q: i for i, q in enumerate(qubits)} expose_acquaintance_gates(strategy) annotated_strategy = strategy.copy() LogicalAnnotator(mapping)(annotated_strategy) new_moments: List['cirq.Moment'] = [] acquaintance_opps: Set[FrozenSet[int]] = set() n_removed = 0 for moment in annotated_strategy: new_moment: List['cirq.Operation'] = [] for op in moment: if isinstance(op, AcquaintanceOperation): opp = frozenset(cast(Sequence[int], op.logical_indices)) if opp not in acquaintance_opps: acquaintance_opps.add(opp) new_moment.append(acquaint(*op.qubits)) else: n_removed += 1 else: new_moment.append(op) new_moments.append(ops.Moment(new_moment)) strategy._moments = new_moments return n_removed
def decompose_matching(self, qubits: Sequence[ops.Qid]) -> ops.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): if (x + 1) % self.part_size: yield swap_gate(*qubits[x:x + 2]) else: yield acquaint(*qubits[x:x + 2])
def cubic_acquaintance_strategy( 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 logical qubits that starts at distance two remains so (except temporarily near the edge), and that every third one `goes through` the pair at some point in the network. The strategy then iterates through a series of mappings in which qubits i and i + k are placed at distance two, for k = 1 through n / 2. Linear swap networks are used in between to effect the permutation. """ qubits = tuple(qubits) n_qubits = len(qubits) swap_gate = SwapPermutationGate(swap_gate) moments = [] index_order = tuple(range(n_qubits)) max_separation = max(((n_qubits - 1) // 2) + 1, 2) for separation in range(1, max_separation): stepped_indices_concatenated = tuple( itertools.chain(*(range(offset, n_qubits, separation) for offset in range(separation)))) new_index_order = skip_and_wrap_around(stepped_indices_concatenated) permutation = { i: new_index_order.index(j) for i, j in enumerate(index_order) } permutation_gate = LinearPermutationGate(n_qubits, permutation, swap_gate) moments.append(ops.Moment([permutation_gate(*qubits)])) for i in range(n_qubits + 1): for offset in range(3): moment = ops.Moment( acquaint(*qubits[j:j + 3]) for j in range(offset, n_qubits - 2, 3)) moments.append(moment) if i < n_qubits: moment = ops.Moment( swap_gate(*qubits[j:j + 2]) for j in range(i % 2, n_qubits - 1, 2)) moments.append(moment) index_order = new_index_order[::-1] return circuits.Circuit(moments, device=UnconstrainedAcquaintanceDevice)
def quartic_paired_acquaintance_strategy( qubit_pairs: Iterable[Tuple['cirq.Qid', ops.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 ) qubits = qubit_pairs_to_qubit_order(qubit_pairs) n_qubits = len(qubits) swap_network = SwapNetworkGate((1,) * n_qubits, 2)(*qubits) strategy = circuits.Circuit(swap_network, device=UnconstrainedAcquaintanceDevice) expose_acquaintance_gates(strategy) for i in reversed(range(0, n_qubits, 2)): moment = ops.Moment([acquaint(*qubits[j : j + 4]) for j in range(i % 4, n_qubits - 3, 4)]) strategy.insert(2 * i, moment) return strategy, qubits