def test_swap_permutation_gate(): no_decomp = lambda op: (isinstance(op, cirq.GateOperation) and op.gate == cirq.SWAP) a, b = cirq.NamedQubit('a'), cirq.NamedQubit('b') expander = cirq.ExpandComposite(no_decomp=no_decomp) circuit = cirq.Circuit.from_ops(SwapPermutationGate()(a, b)) expander(circuit) assert tuple(circuit.all_operations()) == (cirq.SWAP(a, b), ) no_decomp = lambda op: (isinstance(op, cirq.GateOperation) and op.gate == cirq.CZ) expander = cirq.ExpandComposite(no_decomp=no_decomp) circuit = cirq.Circuit.from_ops(SwapPermutationGate(cirq.CZ)(a, b)) expander(circuit) assert tuple(circuit.all_operations()) == (cirq.CZ(a, b), )
def test_update_mapping(): gate = SwapPermutationGate() a, b, c = (cirq.NamedQubit(s) for s in 'abc') mapping = {s: i for i, s in enumerate((a, b, c))} ops = [gate(a, b), gate(b, c)] update_mapping(mapping, ops) assert mapping == {a: 1, b: 2, c: 0}
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 test_validate_permutation_errors(): validate_permutation = PermutationGate.validate_permutation validate_permutation({}) with pytest.raises(IndexError, message='key and value sets must be the same.'): validate_permutation({0: 2, 1: 3}) with pytest.raises( IndexError, message='keys of the permutation must be non-negative.'): validate_permutation({-1: 0, 0: -1}) with pytest.raises(IndexError, message='key is out of bounds.'): validate_permutation({0: 3, 3: 0}, 2) gate = SwapPermutationGate() args = cirq.TextDiagramInfoArgs.UNINFORMED_DEFAULT assert gate.text_diagram_info(args) == NotImplemented
def _decompose_(self, qubits: Sequence[QubitId]) -> OP_TREE: n = len(qubits) left_shift = self.shift % n right_shift = n - left_shift mins = chain(range(left_shift - 1, 0, -1), range(right_shift)) maxs = chain(range(left_shift, n), range(n - 1, right_shift, -1)) swap_gate = SwapPermutationGate(self.swap_gate) for i, j in zip(mins, maxs): for k in range(i, j, 2): yield swap_gate(*qubits[k:k + 2])
def test_diagram(): gate = SwapPermutationGate() a, b = cirq.NamedQubit('a'), cirq.NamedQubit('b') circuit = cirq.Circuit.from_ops([gate(a, b)]) actual_text_diagram = circuit.to_text_diagram() expected_text_diagram = """ a: ───0↦1─── │ b: ───1↦0─── """.strip() assert actual_text_diagram == expected_text_diagram
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 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 test_validate_permutation_errors(): validate_permutation = PermutationGate.validate_permutation validate_permutation({}) with pytest.raises(IndexError, message='key and value sets must be the same.'): validate_permutation({0: 2, 1: 3}) with pytest.raises(IndexError, message='keys of the permutation must be non-negative.'): validate_permutation({-1: 0, 0: -1}) with pytest.raises(IndexError, message='key is out of bounds.'): validate_permutation({0: 3, 3: 0}, 2) gate = SwapPermutationGate() assert cirq.circuit_diagram_info(gate, default=None) is None
def acquaint_insides( swap_gate: 'cirq.Gate', acquaintance_gate: 'cirq.Operation', qubits: Sequence['cirq.Qid'], before: bool, layers: Layers, mapping: Dict[ops.Qid, int], ) -> None: """Acquaints each of the qubits with another set specified by an acquaintance gate. Args: qubits: The list of qubits of which half are individually acquainted with another list of qubits. layers: The layers to put gates into. acquaintance_gate: The acquaintance gate that acquaints the end qubit with another list of qubits. before: Whether the acquainting is done before the shift. swap_gate: The gate used to swap logical indices. mapping: The mapping from qubits to logical indices. Used to keep track of the effect of inside-acquainting swaps. """ max_reach = _get_max_reach(len(qubits), round_up=before) reaches = itertools.chain(range(1, max_reach + 1), range(max_reach, -1, -1)) offsets = (0, 1) * max_reach swap_gate = SwapPermutationGate(swap_gate) ops = [] for offset, reach in zip(offsets, reaches): if offset == before: ops.append(acquaintance_gate) for dr in range(offset, reach, 2): ops.append(swap_gate(*qubits[dr:dr + 2])) intrastitial_layer = getattr(layers, 'pre' if before else 'post') intrastitial_layer += ops # add interstitial gate interstitial_layer = getattr(layers, ('prior' if before else 'posterior') + '_interstitial') interstitial_layer.append(acquaintance_gate) # update mapping reached_qubits = qubits[:max_reach + 1] positions = list(mapping[q] for q in reached_qubits) mapping.update(zip(reached_qubits, reversed(positions)))
def test_rectification(): qubits = cirq.LineQubit.range(4) with pytest.raises(TypeError): rectify_acquaintance_strategy(cirq.Circuit()) perm_gate = SwapPermutationGate() operations = [ perm_gate(*qubits[:2]), ACQUAINT(*qubits[2:]), ACQUAINT(*qubits[:2]), perm_gate(*qubits[2:]) ] strategy = cirq.Circuit.from_ops(operations, device=UnconstrainedAcquaintanceDevice) rectify_acquaintance_strategy(strategy) actual_text_diagram = strategy.to_text_diagram().strip() expected_text_diagram = """ 0: ───────0↦1─────────█─── │ │ 1: ───────1↦0─────────█─── 2: ───█─────────0↦1─────── │ │ 3: ───█─────────1↦0─────── """.strip() assert actual_text_diagram == expected_text_diagram strategy = cirq.Circuit.from_ops(operations, device=UnconstrainedAcquaintanceDevice) rectify_acquaintance_strategy(strategy, False) actual_text_diagram = strategy.to_text_diagram() expected_text_diagram = """ 0: ───0↦1───────█───────── │ │ 1: ───1↦0───────█───────── 2: ─────────█───────0↦1─── │ │ 3: ─────────█───────1↦0─── """.strip() assert actual_text_diagram == expected_text_diagram