Beispiel #1
0
    def test_already_mapped_1(self):
        """Circuit not remapped if matches topology.

        See: https://github.com/Qiskit/qiskit-terra/issues/342
        """
        backend = FakeRueschlikon()
        coupling_map = backend.configuration().coupling_map
        basis_gates = backend.configuration().basis_gates

        qr = QuantumRegister(16, 'qr')
        cr = ClassicalRegister(16, 'cr')
        qc = QuantumCircuit(qr, cr)
        qc.cx(qr[3], qr[14])
        qc.cx(qr[5], qr[4])
        qc.h(qr[9])
        qc.cx(qr[9], qr[8])
        qc.x(qr[11])
        qc.cx(qr[3], qr[4])
        qc.cx(qr[12], qr[11])
        qc.cx(qr[13], qr[4])
        qc.measure(qr, cr)

        new_qc = transpile(qc,
                           coupling_map=coupling_map,
                           basis_gates=basis_gates,
                           initial_layout=Layout.generate_trivial_layout(qr))
        cx_qubits = [
            qargs for (gate, qargs, _) in new_qc.data if gate.name == "cx"
        ]
        cx_qubits_physical = [[ctrl.index, tgt.index]
                              for [ctrl, tgt] in cx_qubits]
        self.assertEqual(sorted(cx_qubits_physical),
                         [[3, 4], [3, 14], [5, 4], [9, 8], [12, 11], [13, 4]])
Beispiel #2
0
    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 test_final_measurement_barrier_for_devices(self, mock_pass):
        """Verify BarrierBeforeFinalMeasurements pass is called in default pipeline for devices."""

        circ = QuantumCircuit.from_qasm_file(self._get_resource_path('example.qasm', Path.QASMS))
        layout = Layout.generate_trivial_layout(*circ.qregs)
        transpile(circ, coupling_map=FakeRueschlikon().configuration().coupling_map,
                  initial_layout=layout)

        self.assertTrue(mock_pass.called)
Beispiel #4
0
    def swap_decompose(self, dag: DAGCircuit, node: DAGOpNode,
                       current_layout: Layout,
                       swap_strategy: SwapStrategy) -> DAGCircuit:
        """Take an instance of :class:`.Commuting2qBlock` and map it to the coupling map.

        The mapping is done with the swap strategy.

        Args:
            dag: The dag which contains the :class:`.Commuting2qBlock` we route.
            node: A node whose operation is a :class:`.Commuting2qBlock`.
            current_layout: The layout before the swaps are applied. This function will
                modify the layout so that subsequent gates can be properly composed on the dag.
            swap_strategy: The swap strategy used to decompose the node.

        Returns:
            A dag that is compatible with the coupling map where swap gates have been added
            to map the gates in the :class:`.Commuting2qBlock` to the hardware.
        """
        trivial_layout = Layout.generate_trivial_layout(*dag.qregs.values())
        gate_layers = self._make_op_layers(dag, node.op, current_layout,
                                           swap_strategy)

        # Iterate over and apply gate layers
        max_distance = max(gate_layers.keys())

        circuit_with_swap = QuantumCircuit(len(dag.qubits))

        for i in range(max_distance + 1):
            # Get current layer and replace the problem indices j,k by the corresponding
            # positions in the coupling map. The current layer corresponds
            # to all the gates that can be applied at the ith swap layer.
            current_layer = {}
            for (j, k), local_gate in gate_layers.get(i, {}).items():
                current_layer[self._position_in_cmap(
                    j, k, current_layout)] = local_gate

            # Not all gates that are applied at the ith swap layer can be applied at the same
            # time. We therefore greedily build sub-layers.
            sub_layers = self._build_sub_layers(current_layer)

            # Apply sub-layers
            for sublayer in sub_layers:
                for edge, local_gate in sublayer.items():
                    circuit_with_swap.append(local_gate, edge)

            # Apply SWAP gates
            if i < max_distance:
                for swap in swap_strategy.swap_layer(i):
                    (j, k) = [
                        trivial_layout.get_physical_bits()[vertex]
                        for vertex in swap
                    ]

                    circuit_with_swap.swap(j, k)
                    current_layout.swap(j, k)

        return circuit_to_dag(circuit_with_swap)
Beispiel #5
0
    def run(self, dag):
        """Run one pass of the lookahead mapper on the provided DAG.

        Args:
            dag (DAGCircuit): the directed acyclic graph to be mapped
        Returns:
            DAGCircuit: A dag mapped to be compatible with the coupling_map in
                the property_set.
        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG
        """
        coupling_map = self._coupling_map
        ordered_virtual_gates = list(dag.serial_layers())

        if self.initial_layout is None:
            if self.property_set["layout"]:
                self.initial_layout = self.property_set["layout"]
            else:
                self.initial_layout = Layout.generate_trivial_layout(
                    *dag.qregs.values())

        if len(dag.qubits()) != len(self.initial_layout):
            raise TranspilerError(
                'The layout does not match the amount of qubits in the DAG')

        if len(self._coupling_map.physical_qubits) != len(self.initial_layout):
            raise TranspilerError(
                "Mappers require to have the layout to be the same size as the coupling map"
            )

        mapped_gates = []
        layout = self.initial_layout.copy()
        gates_remaining = ordered_virtual_gates.copy()

        while gates_remaining:
            best_step = _search_forward_n_swaps(layout, gates_remaining,
                                                coupling_map)

            layout = best_step['layout']
            gates_mapped = best_step['gates_mapped']
            gates_remaining = best_step['gates_remaining']

            mapped_gates.extend(gates_mapped)

        # Preserve input DAG's name, regs, wire_map, etc. but replace the graph.
        mapped_dag = _copy_circuit_metadata(dag, coupling_map)

        for node in mapped_gates:
            mapped_dag.apply_operation_back(op=node.op,
                                            qargs=node.qargs,
                                            cargs=node.cargs)

        return mapped_dag
Beispiel #6
0
    def run(self, dag):
        """
        Flips the cx nodes to match the directed coupling map.
        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.
        """
        new_dag = DAGCircuit()

        if self.layout is None:
            # LegacySwap renames the register in the DAG and does not match the property set
            self.layout = Layout.generate_trivial_layout(*dag.qregs.values())

        for layer in dag.serial_layers():
            subdag = layer['graph']

            for cnot_node in subdag.named_nodes('cx', 'CX'):
                control = cnot_node.qargs[0]
                target = cnot_node.qargs[1]

                physical_q0 = self.layout[control]
                physical_q1 = self.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 self.coupling_map.get_edges():
                    # A flip needs to be done

                    # Create the involved registers
                    if control[0] not in subdag.qregs.values():
                        subdag.add_qreg(control[0])
                    if target[0] not in subdag.qregs.values():
                        subdag.add_qreg(target[0])

                    # Add H gates around
                    subdag.apply_operation_back(HGate(), [target], [])
                    subdag.apply_operation_back(HGate(), [control], [])
                    subdag.apply_operation_front(HGate(), [target], [])
                    subdag.apply_operation_front(HGate(), [control], [])

                    # Flips the CX
                    cnot_node.qargs[0], cnot_node.qargs[1] = target, control

            new_dag.extend_back(subdag)

        return new_dag
 def test_final_measurement_barrier_for_devices(self):
     """Verify BarrierBeforeFinalMeasurements pass is called in default pipeline for devices."""
     qasm_dir = os.path.join(
         os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
         'qasm')
     circ = QuantumCircuit.from_qasm_file(
         os.path.join(qasm_dir, 'example.qasm'))
     layout = Layout.generate_trivial_layout(*circ.qregs)
     orig_pass = BarrierBeforeFinalMeasurements()
     with patch.object(BarrierBeforeFinalMeasurements, 'run', wraps=orig_pass.run) as mock_pass:
         transpile(circ, coupling_map=FakeRueschlikon().configuration().coupling_map,
                   initial_layout=layout)
         self.assertTrue(mock_pass.called)
Beispiel #8
0
    def run(self, dag):
        """
        Pick a layout by assigning n circuit qubits to device qubits 0, .., n-1.

        Args:
            dag (DAGCircuit): DAG to find layout for.

        Raises:
            TranspilerError: if dag wider than self.coupling_map
        """
        num_dag_qubits = sum([qreg.size for qreg in dag.qregs.values()])
        if num_dag_qubits > self.coupling_map.size():
            raise TranspilerError('Number of qubits greater than device.')
        self.property_set['layout'] = Layout.generate_trivial_layout(*dag.qregs.values())
    def test_do_not_run_cxdirection_with_symmetric_cm(self):
        """When the coupling map is symmetric, do not run CXDirection."""

        circ = QuantumCircuit.from_qasm_file(self._get_resource_path('example.qasm', Path.QASMS))
        layout = Layout.generate_trivial_layout(*circ.qregs)
        coupling_map = []
        for node1, node2 in FakeRueschlikon().configuration().coupling_map:
            coupling_map.append([node1, node2])
            coupling_map.append([node2, node1])

        cxdir_pass = CXDirection(CouplingMap(coupling_map))
        with unittest.mock.patch.object(CXDirection, 'run', wraps=cxdir_pass.run) as mock_pass:
            transpile(circ, coupling_map=coupling_map, initial_layout=layout)
            self.assertFalse(mock_pass.called)
Beispiel #10
0
    def test_ignore_initial_layout(self):
        """Ignoring initial layout even when it is supplied"""
        coupling = CouplingMap([[0, 1], [0, 2]])

        circuit = QuantumCircuit(3)
        circuit.cx(1, 2)

        property_set = {"layout": Layout.generate_trivial_layout(*circuit.qubits)}
        actual = BIPMapping(coupling)(circuit, property_set)

        q = QuantumRegister(3, name="q")
        expected = QuantumCircuit(q)
        expected.cx(q[0], q[1])

        self.assertEqual(expected, actual)
    def test_parameterized_circuit_for_device(self):
        """Verify that a parameterized circuit can be transpiled for a device backend."""
        qr = QuantumRegister(2, name='qr')
        qc = QuantumCircuit(qr)

        theta = Parameter('theta')
        qc.rz(theta, qr[0])

        transpiled_qc = transpile(qc, backend=FakeMelbourne(),
                                  initial_layout=Layout.generate_trivial_layout(qr))

        qr = QuantumRegister(14, 'q')
        expected_qc = QuantumCircuit(qr, global_phase=-1 * theta / 2.0)
        expected_qc.append(U1Gate(theta), [qr[0]])

        self.assertEqual(expected_qc, transpiled_qc)
    def test_do_not_run_gatedirection_with_symmetric_cm(self):
        """When the coupling map is symmetric, do not run GateDirection."""
        qasm_dir = os.path.join(
            os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
            'qasm')
        circ = QuantumCircuit.from_qasm_file(
            os.path.join(qasm_dir, 'example.qasm'))
        layout = Layout.generate_trivial_layout(*circ.qregs)
        coupling_map = []
        for node1, node2 in FakeRueschlikon().configuration().coupling_map:
            coupling_map.append([node1, node2])
            coupling_map.append([node2, node1])

        orig_pass = GateDirection(CouplingMap(coupling_map))
        with patch.object(GateDirection, 'run', wraps=orig_pass.run) as mock_pass:
            transpile(circ, coupling_map=coupling_map, initial_layout=layout)
            self.assertFalse(mock_pass.called)
    def test_parameter_expression_circuit_for_device(self):
        """Verify that a circuit including expressions of parameters can be
        transpiled for a device backend."""
        qr = QuantumRegister(2, name='qr')
        qc = QuantumCircuit(qr)

        theta = Parameter('theta')
        square = theta * theta
        qc.rz(square, qr[0])

        transpiled_qc = transpile(qc, backend=FakeMelbourne(),
                                  initial_layout=Layout.generate_trivial_layout(qr))

        qr = QuantumRegister(14, 'q')
        expected_qc = QuantumCircuit(qr, global_phase=-1 * square / 2.0)
        expected_qc.append(U1Gate(square), [qr[0]])
        self.assertEqual(expected_qc, transpiled_qc)
Beispiel #14
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 self.initial_layout is None:
            if self.property_set["layout"]:
                self.initial_layout = self.property_set["layout"]
            else:
                self.initial_layout = Layout.generate_trivial_layout(
                    *dag.qregs.values())

        if len(dag.qubits()) != len(self.initial_layout):
            raise TranspilerError(
                'The layout does not match the amount of qubits in the DAG')

        if len(self.coupling_map.physical_qubits) != len(self.initial_layout):
            raise TranspilerError(
                "Mappers require to have the layout to be the same size as the coupling map"
            )

        self.input_layout = self.initial_layout.copy()

        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)
        # self.property_set["layout"] = self.initial_layout
        return new_dag
Beispiel #15
0
    def run(self, dag):
        """
        If `dag` is mapped to `coupling_map`, the property
        `is_swap_mapped` is set to True (or to False otherwise).

        Args:
            dag (DAGCircuit): DAG to map.
        """
        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_swap_mapped'] = True

        for gate in dag.twoQ_gates():
            physical_q0 = self.layout[gate.qargs[0]]
            physical_q1 = self.layout[gate.qargs[1]]

            if self.coupling_map.distance(physical_q0, physical_q1) != 1:
                self.property_set['is_swap_mapped'] = False
                return
Beispiel #16
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the pass by decomposing the nodes it applies on.

        Args:
            dag: The dag to which we will add swaps.

        Returns:
            A dag where swaps have been added for the intended gate type.

        Raises:
            TranspilerError: If the swap strategy was not given at init time and there is
                no swap strategy in the property set.
            TranspilerError: If the quantum circuit contains more than one qubit register.
            TranspilerError: If there are qubits that are not contained in the quantum register.
        """
        if self._swap_strategy is None:
            swap_strategy = self.property_set["swap_strategy"]

            if swap_strategy is None:
                raise TranspilerError(
                    "No swap strategy given at init or in the property set.")
        else:
            swap_strategy = self._swap_strategy

        if len(dag.qregs) != 1:
            raise TranspilerError(
                f"{self.__class__.__name__} runs on circuits with one quantum register."
            )

        if len(dag.qubits) != next(iter(dag.qregs.values())).size:
            raise TranspilerError(
                "Circuit has qubits not contained in the qubit register.")

        new_dag = dag.copy_empty_like()

        current_layout = Layout.generate_trivial_layout(*dag.qregs.values())

        # Used to keep track of nodes that do not decompose using swap strategies.
        accumulator = new_dag.copy_empty_like()

        self._bit_indices = {
            bit: index
            for index, bit in enumerate(dag.qubits)
        }

        for node in dag.topological_op_nodes():
            if isinstance(node.op, Commuting2qBlock):

                # Check that the swap strategy creates enough connectivity for the node.
                self._check_edges(node, swap_strategy)

                # Compose any accumulated non-swap strategy gates to the dag
                accumulator = self._compose_non_swap_nodes(
                    accumulator, current_layout, new_dag)

                # Decompose the swap-strategy node and add to the dag.
                new_dag.compose(
                    self.swap_decompose(dag, node, current_layout,
                                        swap_strategy))
            else:
                accumulator.apply_operation_back(node.op, node.qargs,
                                                 node.cargs)

        self._compose_non_swap_nodes(accumulator, current_layout, new_dag)

        return new_dag
Beispiel #17
0
    def run(self, dag):
        """
        Runs the BasicSwap 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
        """
        new_dag = DAGCircuit()

        if self.initial_layout is None:
            if self.property_set["layout"]:
                self.initial_layout = self.property_set["layout"]
            else:
                self.initial_layout = Layout.generate_trivial_layout(
                    *dag.qregs.values())

        if len(dag.qubits()) != len(self.initial_layout):
            raise TranspilerError(
                'The layout does not match the amount of qubits in the DAG')

        if len(self.coupling_map.physical_qubits) != len(self.initial_layout):
            raise TranspilerError(
                "Mappers require to have the layout to be the same size as the coupling map"
            )

        current_layout = self.initial_layout.copy()

        for layer in dag.serial_layers():
            subdag = layer['graph']

            for gate in subdag.twoQ_gates():
                physical_q0 = current_layout[gate.qargs[0]]
                physical_q1 = current_layout[gate.qargs[1]]
                if self.coupling_map.distance(physical_q0, physical_q1) != 1:
                    # Insert a new layer with the SWAP(s).
                    swap_layer = DAGCircuit()

                    path = self.coupling_map.shortest_undirected_path(
                        physical_q0, physical_q1)
                    for swap in range(len(path) - 2):
                        connected_wire_1 = path[swap]
                        connected_wire_2 = path[swap + 1]

                        qubit_1 = current_layout[connected_wire_1]
                        qubit_2 = current_layout[connected_wire_2]

                        # create qregs
                        for qreg in current_layout.get_registers():
                            if qreg not in swap_layer.qregs.values():
                                swap_layer.add_qreg(qreg)

                        # create the swap operation
                        swap_layer.apply_operation_back(
                            SwapGate(), qargs=[qubit_1, qubit_2], cargs=[])

                    # layer insertion
                    edge_map = current_layout.combine_into_edge_map(
                        self.initial_layout)
                    new_dag.compose_back(swap_layer, edge_map)

                    # update current_layout
                    for swap in range(len(path) - 2):
                        current_layout.swap(path[swap], path[swap + 1])

            edge_map = current_layout.combine_into_edge_map(
                self.initial_layout)
            new_dag.extend_back(subdag, edge_map)

        return new_dag