def test_from_circuit_constructor_reverse_user_specified_layout(self): """Test initialization from a circuit with a user specified reverse layout.""" # Test tensor product of 1-qubit gates circuit = QuantumCircuit(3) circuit.h(2) circuit.x(1) circuit.ry(np.pi / 2, 0) layout = Layout({circuit.qubits[2]: 0, circuit.qubits[1]: 1, circuit.qubits[0]: 2}) op = Operator.from_circuit(circuit, layout=layout) y90 = (1 / np.sqrt(2)) * np.array([[1, -1], [1, 1]]) target = np.kron(y90, np.kron(self.UX, self.UH)) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) self.assertTrue(global_phase_equivalent) # Test decomposition of Controlled-Phase gate lam = np.pi / 4 circuit = QuantumCircuit(2) circuit.cp(lam, 1, 0) layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) op = Operator.from_circuit(circuit, layout=layout) target = np.diag([1, 1, 1, np.exp(1j * lam)]) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) self.assertTrue(global_phase_equivalent) # Test decomposition of controlled-H gate circuit = QuantumCircuit(2) circuit.ch(1, 0) layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) op = Operator.from_circuit(circuit, layout=layout) target = np.kron(self.UI, np.diag([1, 0])) + np.kron(self.UH, np.diag([0, 1])) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) self.assertTrue(global_phase_equivalent)
def run(self, dag): """Run the SabreLayout pass on `dag`. Args: dag (DAGCircuit): DAG to find layout for. Raises: TranspilerError: if dag wider than self.coupling_map """ if len(dag.qubits) > self.coupling_map.size(): raise TranspilerError("More virtual qubits exist than physical.") # Choose a random initial_layout. if self.seed is None: self.seed = np.random.randint(0, np.iinfo(np.int32).max) rng = np.random.default_rng(self.seed) physical_qubits = rng.choice(self.coupling_map.size(), len(dag.qubits), replace=False) physical_qubits = rng.permutation(physical_qubits) initial_layout = Layout( {q: dag.qubits[i] for i, q in enumerate(physical_qubits)}) if self.routing_pass is None: self.routing_pass = SabreSwap(self.coupling_map, "decay", seed=self.seed, fake_run=True) else: self.routing_pass.fake_run = True # Do forward-backward iterations. circ = dag_to_circuit(dag) rev_circ = circ.reverse_ops() for _ in range(self.max_iterations): for _ in ("forward", "backward"): pm = self._layout_and_route_passmanager(initial_layout) new_circ = pm.run(circ) # Update initial layout and reverse the unmapped circuit. pass_final_layout = pm.property_set["final_layout"] final_layout = self._compose_layouts( initial_layout, pass_final_layout, new_circ.qregs # pylint: disable=no-member ) initial_layout = final_layout circ, rev_circ = rev_circ, circ # Diagnostics logger.info("new initial layout") logger.info(initial_layout) for qreg in dag.qregs.values(): initial_layout.add_register(qreg) self.property_set["layout"] = initial_layout self.routing_pass.fake_run = False
def test_layout_add(self): """add() method""" layout = Layout() layout[self.qr[0]] = 0 layout.add(self.qr[1]) self.assertEqual(layout[self.qr[1]], 1)
def test_layout_from_intlist(self): """Create a layout from a list of integers. virtual physical q1_0 -> 4 q2_0 -> 5 q2_1 -> 6 q3_0 -> 8 q3_1 -> 9 q3_2 -> 10 """ qr1 = QuantumRegister(1, 'qr1') qr2 = QuantumRegister(2, 'qr2') qr3 = QuantumRegister(3, 'qr3') intlist_layout = [4, 5, 6, 8, 9, 10] layout = Layout.from_intlist(intlist_layout, qr1, qr2, qr3) expected = Layout({ 4: qr1[0], 5: qr2[0], 6: qr2[1], 8: qr3[0], 9: qr3[1], 10: qr3[2] }) self.assertDictEqual(layout._p2v, expected._p2v) self.assertDictEqual(layout._v2p, expected._v2p)
def test_layout_get_bits(self): """Get the map from the (qu)bits view""" layout_dict = {(self.qr, 0): 0, (self.qr, 1): 1, (self.qr, 2): 2} layout = Layout(layout_dict) self.assertDictEqual(layout_dict, layout.get_virtual_bits())
def test_layout_from_intlist_short(self): """If the intlist is longer that your quantum register, map them to None. virtual physical q1_0 -> 4 q2_0 -> 5 q2_1 -> 6 None -> 8 None -> 9 None -> 10 """ qr1 = QuantumRegister(1, 'qr1') qr2 = QuantumRegister(2, 'qr2') intlist_layout = [4, 5, 6, 8, 9, 10] layout = Layout.from_intlist(intlist_layout, qr1, qr2) expected = Layout({ 4: qr1[0], 5: qr2[0], 6: qr2[1], 8: None, 9: None, 10: None }) self.assertDictEqual(layout._p2v, expected._p2v) self.assertDictEqual(layout._v2p, expected._v2p)
def test_layout_get_physical_bits(self): """Get the map from the physical bits view""" layout = Layout({self.qr[0]: 0, self.qr[1]: 1, self.qr[2]: 2}) self.assertDictEqual(layout.get_physical_bits(), { 0: self.qr[0], 1: self.qr[1], 2: self.qr[2] })
def test_layout_repr_with_holes(self): """A non-bijective Layout repr reproduces layout""" qr = QuantumRegister(5, 'qr') layout = Layout({qr[0]: 0, qr[1]: 3, qr[2]: 4, qr[3]: 5, qr[4]: 6}) repr_layout = eval(layout.__repr__()) # pylint: disable=eval-used self.assertDictEqual(layout._p2v, repr_layout._p2v) self.assertDictEqual(layout._v2p, repr_layout._v2p)
def test_layout_add(self): """add() method""" layout = Layout() layout[(self.qr, 0)] = 0 layout.add((self.qr, 1)) self.assertEqual(layout[(self.qr, 1)], 1) self.assertEqual(layout[1], (self.qr, 1))
def test_layout_get_physical_bits(self): """Get the map from the physical bits view""" layout = Layout({(self.qr, 0): 0, (self.qr, 1): 1, (self.qr, 2): 2}) self.assertDictEqual(layout.get_physical_bits(), { 0: (self.qr, 0), 1: (self.qr, 1), 2: (self.qr, 2) })
def run(self, dag): """Run the SabreLayout pass on `dag`. Args: dag (DAGCircuit): DAG to find layout for. Raises: TranspilerError: if dag wider than self.coupling_map """ if len(dag.qubits) > self.coupling_map.size(): raise TranspilerError('More virtual qubits exist than physical.') # Choose a random initial_layout. if self.seed is None: self.seed = np.random.randint(0, np.iinfo(np.int32).max) rng = np.random.default_rng(self.seed) physical_qubits = rng.choice(self.coupling_map.size(), len(dag.qubits), replace=False) physical_qubits = rng.permutation(physical_qubits) initial_layout = Layout( {q: dag.qubits[i] for i, q in enumerate(physical_qubits)}) if self.routing_pass is None: self.routing_pass = SabreSwap(self.coupling_map, 'decay', seed=self.seed) # Do forward-backward iterations. circ = dag_to_circuit(dag) for i in range(self.max_iterations): for _ in ('forward', 'backward'): pm = self._layout_and_route_passmanager(initial_layout) new_circ = pm.run(circ) # Update initial layout and reverse the unmapped circuit. pass_final_layout = pm.property_set['final_layout'] final_layout = self._compose_layouts(initial_layout, pass_final_layout, new_circ.qregs) # pylint: disable=no-member initial_layout = final_layout circ = circ.reverse_ops() # Diagnostics logger.info('After round %d, num_swaps: %d', i + 1, new_circ.count_ops().get('swap', 0)) # pylint: disable=no-member logger.info('new initial layout') logger.info(initial_layout) for qreg in dag.qregs.values(): initial_layout.add_register(qreg) self.property_set['layout'] = initial_layout
def test_layout_contains(self): """Verify Layouts support __contains__.""" qr = QuantumRegister(2, 'qr') layout = Layout() layout.add(qr[0], 0) self.assertIn(qr[0], layout) self.assertIn(0, layout) self.assertNotIn(qr[1], layout) self.assertNotIn(1, layout)
def test_layout_add_register(self): """add_register() method""" layout = Layout() qr0 = QuantumRegister(2, 'q0') qr1 = QuantumRegister(1, 'qr1') layout.add_register(qr0) layout.add_register(qr1) self.assertEqual(layout[qr0[0]], 0) self.assertEqual(layout[qr0[1]], 1) self.assertEqual(layout[qr1[0]], 2)
def test_layout_from_intlist_numpy(self): """Create a layout from a list of numpy integers. See #3097""" qr1 = QuantumRegister(1, "qr1") qr2 = QuantumRegister(2, "qr2") qr3 = QuantumRegister(3, "qr3") intlist_layout = numpy.array([0, 1, 2, 3, 4, 5]) layout = Layout.from_intlist(intlist_layout, qr1, qr2, qr3) expected = Layout.generate_trivial_layout(qr1, qr2, qr3) self.assertDictEqual(layout._p2v, expected._p2v) self.assertDictEqual(layout._v2p, expected._v2p)
def test_layout_repr(self): """Layout repr reproduces layout""" qr = QuantumRegister(5, 'qr') layout = Layout({(qr, 0): 2, (qr, 1): 4, (qr, 2): 3, (qr, 3): 0, (qr, 4): 1, }) repr_layout = eval(layout.__repr__()) # pylint: disable=eval-used self.assertDictEqual(layout._p2v, repr_layout._p2v) self.assertDictEqual(layout._v2p, repr_layout._v2p)
def test_layout_add_register(self): """add_register() method""" layout = Layout() qr0 = QuantumRegister(2, "q0") qr1 = QuantumRegister(1, "qr1") layout.add_register(qr0) layout.add_register(qr1) self.assertEqual(layout[qr0[0]], 0) self.assertEqual(layout[qr0[1]], 1) self.assertEqual(layout[qr1[0]], 2) self.assertIn(qr0, layout.get_registers()) self.assertIn(qr1, layout.get_registers())
def test_layout_combine(self): """combine_into_edge_map() method""" layout = Layout() layout.add((self.qr, 0)) layout.add((self.qr, 1)) another_layout = Layout() another_layout.add((self.qr, 1)) another_layout.add((self.qr, 0)) edge_map = layout.combine_into_edge_map(another_layout) self.assertDictEqual(edge_map, {(self.qr, 0): (self.qr, 1), (self.qr, 1): (self.qr, 0)})
def test_layout_combine(self): """combine_into_edge_map() method""" layout = Layout() layout.add(self.qr[0]) layout.add(self.qr[1]) another_layout = Layout() another_layout.add(self.qr[1]) another_layout.add(self.qr[0]) edge_map = layout.combine_into_edge_map(another_layout) self.assertDictEqual(edge_map, {self.qr[0]: self.qr[1], self.qr[1]: self.qr[0]})
def run(self, dag): """ Run the StochasticSwap pass on `dag`. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: A mapped DAG. Raises: TranspilerError: if the coupling map or the layout are not compatible with the DAG """ if len(dag.qregs) != 1 or dag.qregs.get('q', None) is None: raise TranspilerError('Basic swap runs on physical circuits only') if len(dag.qubits()) > len(self.coupling_map.physical_qubits): raise TranspilerError( 'The layout does not match the amount of qubits in the DAG') canonical_register = dag.qregs['q'] self.trivial_layout = Layout.generate_trivial_layout( canonical_register) self.qregs = dag.qregs if self.seed is None: self.seed = np.random.randint(0, np.iinfo(np.int32).max) self.rng = np.random.RandomState(self.seed) logger.debug("StochasticSwap RandomState seeded with seed=%s", self.seed) new_dag = self._mapper(dag, self.coupling_map, trials=self.trials) return new_dag
def run(self, dag): """Run the CXDirection pass on `dag`. Flips the cx nodes to match the directed coupling map. Modifies the input dag. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: The rearranged dag for the coupling map Raises: TranspilerError: If the circuit cannot be mapped just by flipping the cx nodes. """ cmap_edges = set(self.coupling_map.get_edges()) if len(dag.qregs) > 1: raise TranspilerError( 'CXDirection expects a single qreg input DAG,' 'but input DAG had qregs: {}.'.format(dag.qregs)) trivial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) for cnot_node in dag.named_nodes('cx', 'CX'): control = cnot_node.qargs[0] target = cnot_node.qargs[1] physical_q0 = trivial_layout[control] physical_q1 = trivial_layout[target] if self.coupling_map.distance(physical_q0, physical_q1) != 1: raise TranspilerError( 'The circuit requires a connection between physical ' 'qubits %s and %s' % (physical_q0, physical_q1)) if (physical_q0, physical_q1) not in cmap_edges: # A flip needs to be done # Create the replacement dag and associated register. sub_dag = DAGCircuit() sub_qr = QuantumRegister(2) sub_dag.add_qreg(sub_qr) # Add H gates before sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[0]], []) sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[1]], []) # Flips the cx sub_dag.apply_operation_back(CXGate(), [sub_qr[1], sub_qr[0]], []) # Add H gates after sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[0]], []) sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[1]], []) dag.substitute_node_with_dag(cnot_node, sub_dag) return dag
def test_layout_avoid_dangling_virtual(self): """ No dangling pointers for virtual qubits.""" layout = Layout({self.qr[0]: 0}) self.assertEqual(layout[0], self.qr[0]) layout[0] = self.qr[1] with self.assertRaises(KeyError): _ = layout[self.qr[0]]
def test_virtual_keyerror(self): """When asking for an unexistant virtual qubit, KeyError""" layout = Layout() layout[self.qr[0]] = 1 with self.assertRaises(KeyError): _ = layout[self.qr[1]]
def test_from_circuit_constructor_ghz_out_of_order_layout(self): """Test an out of order ghz state with a layout set.""" circuit = QuantumCircuit(5) circuit.h(3) circuit.cx(3, 4) circuit.cx(3, 2) circuit.cx(3, 0) circuit.cx(3, 1) circuit._layout = Layout( { circuit.qubits[3]: 0, circuit.qubits[4]: 1, circuit.qubits[2]: 2, circuit.qubits[0]: 3, circuit.qubits[1]: 4, } ) result = Operator.from_circuit(circuit) expected = QuantumCircuit(5) expected.h(0) expected.cx(0, 1) expected.cx(0, 2) expected.cx(0, 3) expected.cx(0, 4) expected_op = Operator(expected) self.assertTrue(expected_op.equiv(result))
def test_physical_keyerror(self): """When asking for an unexistant physical qubit, KeyError""" layout = Layout() layout[(self.qr, 0)] = 1 with self.assertRaises(KeyError): _ = layout[0]
def test_layout_avoid_dangling_virtual(self): """ No dangling pointers for virtual qubits.""" layout = Layout({(self.qr, 0): 0}) self.assertEqual(layout[0], (self.qr, 0)) layout[0] = (self.qr, 1) with self.assertRaises(KeyError): _ = layout[(self.qr, 0)]
def remap_compact_virtual_qubit_registers(circuit: QuantumCircuit, coupling_map: CouplingMap) -> \ Optional[Tuple[QuantumCircuit, int]]: dag = circuit_to_dag(circuit) if not check_dag_circuit_compatible(dag, coupling_map): return qreg = dag.qregs['q'] num_physical_qubits = len(coupling_map.physical_qubits) device_register = QuantumRegister(num_physical_qubits) qubit_index_counter = 0 virtual_qubit_remap_layout = Layout.generate_trivial_layout(device_register) idle_wires = [wire for wire in dag.idle_wires()] for i in range(len(qreg)): qubit = qreg[i] if qubit not in idle_wires: virtual_qubit_remap_layout.add(qubit, qubit_index_counter) qubit_index_counter += 1 for i, wire in enumerate(idle_wires): virtual_qubit_remap_layout.add(wire, qubit_index_counter + i) logger.debug("Compact circuit layout: {}".format(virtual_qubit_remap_layout)) remap_pass_manager = PassManager() remap_pass_manager.append(SetLayout(virtual_qubit_remap_layout)) remap_pass_manager.append(ApplyLayout()) remap_circuit = remap_pass_manager.run(circuit) return remap_circuit, qubit_index_counter
def run(self, dag): """ If `dag` is mapped and the direction is correct the property `is_direction_mapped` is set to True (or to False otherwise). Args: dag (DAGCircuit): DAG to check. """ if self.layout is None: if self.property_set["layout"]: self.layout = self.property_set["layout"] else: self.layout = Layout.generate_trivial_layout(*dag.qregs.values()) self.property_set['is_direction_mapped'] = True edges = self.coupling_map.get_edges() for gate in dag.twoQ_gates(): physical_q0 = self.layout[gate.qargs[0]] physical_q1 = self.layout[gate.qargs[1]] if isinstance(gate.op, (CXBase, CnotGate)) and ( physical_q0, physical_q1) not in edges: self.property_set['is_direction_mapped'] = False return
def layout_test(): q0 = QuantumRegister(1, name='x') q1 = QuantumRegister(1, name='y') q2 = QuantumRegister(1, name='z') q3 = QuantumRegister(1, name='h') cr = ClassicalRegister(4) qc = QuantumCircuit(q0, q1, q2, q3, cr) qc.x(q0[0]) qc.y(q1[0]) qc.z(q2[0]) qc.h(q3[0]) qc.measure(q0, cr[0]) # qc = random_circuit(4, 1, measure=True) print(qc) q = qc.qubits print(q) input_dict = {} input_dict[q0[0]] = 3 input_dict[q1[0]] = 2 input_dict[q2[0]] = 1 input_dict[q3[0]] = 0 # input_dict[q[0]] = 3 # input_dict[q[1]] = 2 # input_dict[q[2]] = 1 # input_dict[q[3]] = 0 layout = Layout(input_dict=input_dict) print(layout) qc._layout = layout print(qc) print(qc._layout)
def run(self, dag): """Run the CheckGateDirection pass on `dag`. If `dag` is mapped and the direction is correct the property `is_direction_mapped` is set to True (or to False otherwise). Args: dag (DAGCircuit): DAG to check. """ self.property_set["is_direction_mapped"] = True edges = self.coupling_map.get_edges() trivial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) if self.target is None: for gate in dag.two_qubit_ops(): physical_q0 = trivial_layout[gate.qargs[0]] physical_q1 = trivial_layout[gate.qargs[1]] if (physical_q0, physical_q1) not in edges: self.property_set["is_direction_mapped"] = False return else: for gate in dag.two_qubit_ops(): physical_q0 = trivial_layout[gate.qargs[0]] physical_q1 = trivial_layout[gate.qargs[1]] if (physical_q0, physical_q1) not in self.target[gate.op.name]: self.property_set["is_direction_mapped"] = False return
def run(self, dag): """Run the StochasticSwap pass on `dag`. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: A mapped DAG. Raises: TranspilerError: if the coupling map or the layout are not compatible with the DAG """ if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None: raise TranspilerError("StochasticSwap runs on physical circuits only") if len(dag.qubits) > len(self.coupling_map.physical_qubits): raise TranspilerError("The layout does not match the amount of qubits in the DAG") canonical_register = dag.qregs["q"] self.trivial_layout = Layout.generate_trivial_layout(canonical_register) self._qubit_indices = {bit: idx for idx, bit in enumerate(dag.qubits)} self.qregs = dag.qregs if self.seed is None: self.seed = np.random.randint(0, np.iinfo(np.int32).max) self.rng = np.random.default_rng(self.seed) logger.debug("StochasticSwap default_rng seeded with seed=%s", self.seed) self.coupling_map.compute_distance_matrix() new_dag = self._mapper(dag, self.coupling_map, trials=self.trials) return new_dag