示例#1
0
    def run(self, dag):
        """run the layout method"""
        qubits = dag.qubits
        qubit_indices = {qubit: index for index, qubit in enumerate(qubits)}

        interactions = []
        for node in dag.op_nodes(include_directives=False):
            len_args = len(node.qargs)
            if len_args == 2:
                interactions.append((qubit_indices[node.qargs[0]],
                                     qubit_indices[node.qargs[1]]))
            if len_args >= 3:
                raise TranspilerError(
                    "VF2Layout only can handle 2-qubit gates or less. Node "
                    f"{node.name} ({node}) is {len_args}-qubit")

        if self.strict_direction:
            cm_graph = self.coupling_map.graph
            im_graph = PyDiGraph(multigraph=False)
        else:
            cm_graph = self.coupling_map.graph.to_undirected()
            im_graph = PyGraph(multigraph=False)

        cm_nodes = list(cm_graph.node_indexes())
        if self.seed != -1:
            random.Random(self.seed).shuffle(cm_nodes)
            shuffled_cm_graph = type(cm_graph)()
            shuffled_cm_graph.add_nodes_from(cm_nodes)
            new_edges = [(cm_nodes[edge[0]], cm_nodes[edge[1]])
                         for edge in cm_graph.edge_list()]
            shuffled_cm_graph.add_edges_from_no_data(new_edges)
            cm_nodes = [
                k for k, v in sorted(enumerate(cm_nodes),
                                     key=lambda item: item[1])
            ]
            cm_graph = shuffled_cm_graph
        im_graph.add_nodes_from(range(len(qubits)))
        im_graph.add_edges_from_no_data(interactions)

        mappings = vf2_mapping(cm_graph,
                               im_graph,
                               subgraph=True,
                               id_order=False,
                               induced=False)
        try:
            mapping = next(mappings)
            stop_reason = "solution found"
            layout = Layout({
                qubits[im_i]: cm_nodes[cm_i]
                for cm_i, im_i in mapping.items()
            })
            self.property_set["layout"] = layout
            for reg in dag.qregs.values():
                self.property_set["layout"].add_register(reg)
        except StopIteration:
            stop_reason = "nonexistent solution"

        self.property_set["VF2Layout_stop_reason"] = stop_reason
    def run(self, dag):
        """run the layout method"""
        if self.target is None and (self.coupling_map is None or self.properties is None):
            raise TranspilerError(
                "A target must be specified or a coupling map and properties must be provided"
            )
        if not self.strict_direction and self.avg_error_map is None:
            self.avg_error_map = vf2_utils.build_average_error_map(
                self.target, self.properties, self.coupling_map
            )
        result = vf2_utils.build_interaction_graph(dag, self.strict_direction)
        if result is None:
            self.property_set["VF2PostLayout_stop_reason"] = VF2PostLayoutStopReason.MORE_THAN_2Q
            return
        im_graph, im_graph_node_map, reverse_im_graph_node_map = result

        if self.target is not None:
            if self.strict_direction:
                cm_graph = PyDiGraph(multigraph=False)
            else:
                cm_graph = PyGraph(multigraph=False)
            cm_graph.add_nodes_from(
                [self.target.operation_names_for_qargs((i,)) for i in range(self.target.num_qubits)]
            )
            for qargs in self.target.qargs:
                len_args = len(qargs)
                # If qargs == 1 we already populated it and if qargs > 2 there are no instructions
                # using those in the circuit because we'd have already returned by this point
                if len_args == 2:
                    cm_graph.add_edge(
                        qargs[0], qargs[1], self.target.operation_names_for_qargs(qargs)
                    )
            cm_nodes = list(cm_graph.node_indexes())
        else:
            cm_graph, cm_nodes = vf2_utils.shuffle_coupling_graph(
                self.coupling_map, self.seed, self.strict_direction
            )

        logger.debug("Running VF2 to find post transpile mappings")
        if self.target and self.strict_direction:
            mappings = vf2_mapping(
                cm_graph,
                im_graph,
                node_matcher=_target_match,
                edge_matcher=_target_match,
                subgraph=True,
                id_order=False,
                induced=False,
                call_limit=self.call_limit,
            )
        else:
            mappings = vf2_mapping(
                cm_graph,
                im_graph,
                subgraph=True,
                id_order=False,
                induced=False,
                call_limit=self.call_limit,
            )
        chosen_layout = None
        initial_layout = Layout(dict(enumerate(dag.qubits)))
        try:
            if self.strict_direction:
                chosen_layout_score = self._score_layout(
                    initial_layout, im_graph_node_map, reverse_im_graph_node_map, im_graph
                )
            else:
                chosen_layout_score = vf2_utils.score_layout(
                    self.avg_error_map,
                    initial_layout,
                    im_graph_node_map,
                    reverse_im_graph_node_map,
                    im_graph,
                    self.strict_direction,
                )
        # Circuit not in basis so we have nothing to compare against return here
        except KeyError:
            self.property_set[
                "VF2PostLayout_stop_reason"
            ] = VF2PostLayoutStopReason.NO_SOLUTION_FOUND
            return

        logger.debug("Initial layout has score %s", chosen_layout_score)

        start_time = time.time()
        trials = 0
        for mapping in mappings:
            trials += 1
            logger.debug("Running trial: %s", trials)
            stop_reason = VF2PostLayoutStopReason.SOLUTION_FOUND
            layout = Layout(
                {reverse_im_graph_node_map[im_i]: cm_nodes[cm_i] for cm_i, im_i in mapping.items()}
            )
            if self.strict_direction:
                layout_score = self._score_layout(
                    layout, im_graph_node_map, reverse_im_graph_node_map, im_graph
                )
            else:
                layout_score = vf2_utils.score_layout(
                    self.avg_error_map,
                    layout,
                    im_graph_node_map,
                    reverse_im_graph_node_map,
                    im_graph,
                    self.strict_direction,
                )
            logger.debug("Trial %s has score %s", trials, layout_score)
            if layout_score < chosen_layout_score:
                logger.debug(
                    "Found layout %s has a lower score (%s) than previous best %s (%s)",
                    layout,
                    layout_score,
                    chosen_layout,
                    chosen_layout_score,
                )
                chosen_layout = layout
                chosen_layout_score = layout_score
            elapsed_time = time.time() - start_time
            if self.time_limit is not None and elapsed_time >= self.time_limit:
                logger.debug(
                    "VFPostLayout has taken %s which exceeds configured max time: %s",
                    elapsed_time,
                    self.time_limit,
                )
                break
        if chosen_layout is None:
            stop_reason = VF2PostLayoutStopReason.NO_SOLUTION_FOUND
        else:
            existing_layout = self.property_set["layout"]
            # If any ancillas in initial layout map them back to the final layout output
            if existing_layout is not None and len(existing_layout) > len(chosen_layout):
                virtual_bits = chosen_layout.get_virtual_bits()
                used_bits = set(virtual_bits.values())
                num_qubits = len(cm_graph)
                for bit in dag.qubits:
                    if len(chosen_layout) == len(existing_layout):
                        break
                    if bit not in virtual_bits:
                        for i in range(num_qubits):
                            if i not in used_bits:
                                used_bits.add(i)
                                chosen_layout.add(bit, i)
                                break
            self.property_set["post_layout"] = chosen_layout

        self.property_set["VF2PostLayout_stop_reason"] = stop_reason
示例#3
0
    def run(self, dag):
        """run the layout method"""
        if self.coupling_map is None:
            raise TranspilerError("coupling_map or target must be specified.")

        qubits = dag.qubits
        qubit_indices = {qubit: index for index, qubit in enumerate(qubits)}

        interactions = []
        for node in dag.op_nodes(include_directives=False):
            len_args = len(node.qargs)
            if len_args == 2:
                interactions.append((qubit_indices[node.qargs[0]],
                                     qubit_indices[node.qargs[1]]))
            if len_args >= 3:
                self.property_set[
                    "VF2Layout_stop_reason"] = VF2LayoutStopReason.MORE_THAN_2Q
                return

        if self.strict_direction:
            cm_graph = self.coupling_map.graph
            im_graph = PyDiGraph(multigraph=False)
        else:
            cm_graph = self.coupling_map.graph.to_undirected()
            im_graph = PyGraph(multigraph=False)

        cm_nodes = list(cm_graph.node_indexes())
        if self.seed != -1:
            random.Random(self.seed).shuffle(cm_nodes)
            shuffled_cm_graph = type(cm_graph)()
            shuffled_cm_graph.add_nodes_from(cm_nodes)
            new_edges = [(cm_nodes[edge[0]], cm_nodes[edge[1]])
                         for edge in cm_graph.edge_list()]
            shuffled_cm_graph.add_edges_from_no_data(new_edges)
            cm_nodes = [
                k for k, v in sorted(enumerate(cm_nodes),
                                     key=lambda item: item[1])
            ]
            cm_graph = shuffled_cm_graph

        im_graph.add_nodes_from(range(len(qubits)))
        im_graph.add_edges_from_no_data(interactions)
        # To avoid trying to over optimize the result by default limit the number
        # of trials based on the size of the graphs. For circuits with simple layouts
        # like an all 1q circuit we don't want to sit forever trying every possible
        # mapping in the search space
        if self.max_trials is None:
            im_graph_edge_count = len(im_graph.edge_list())
            cm_graph_edge_count = len(cm_graph.edge_list())
            self.max_trials = max(im_graph_edge_count,
                                  cm_graph_edge_count) + 15

        logger.debug("Running VF2 to find mappings")
        mappings = vf2_mapping(
            cm_graph,
            im_graph,
            subgraph=True,
            id_order=False,
            induced=False,
            call_limit=self.call_limit,
        )
        chosen_layout = None
        chosen_layout_score = None
        start_time = time.time()
        trials = 0
        for mapping in mappings:
            trials += 1
            logger.debug("Running trial: %s", trials)
            stop_reason = VF2LayoutStopReason.SOLUTION_FOUND
            layout = Layout({
                qubits[im_i]: cm_nodes[cm_i]
                for cm_i, im_i in mapping.items()
            })
            # If the graphs have the same number of nodes we don't need to score or do multiple
            # trials as the score heuristic currently doesn't weigh nodes based on gates on a
            # qubit so the scores will always all be the same
            if len(cm_graph) == len(im_graph):
                chosen_layout = layout
                break
            layout_score = self._score_layout(layout)
            logger.debug("Trial %s has score %s", trials, layout_score)
            if chosen_layout is None:
                chosen_layout = layout
                chosen_layout_score = layout_score
            elif layout_score < chosen_layout_score:
                logger.debug(
                    "Found layout %s has a lower score (%s) than previous best %s (%s)",
                    layout,
                    layout_score,
                    chosen_layout,
                    chosen_layout_score,
                )
                chosen_layout = layout
                chosen_layout_score = layout_score
            if self.max_trials > 0 and trials >= self.max_trials:
                logger.debug("Trial %s is >= configured max trials %s", trials,
                             self.max_trials)
                break
            elapsed_time = time.time() - start_time
            if self.time_limit is not None and elapsed_time >= self.time_limit:
                logger.debug(
                    "VF2Layout has taken %s which exceeds configured max time: %s",
                    elapsed_time,
                    self.time_limit,
                )
                break
        if chosen_layout is None:
            stop_reason = VF2LayoutStopReason.NO_SOLUTION_FOUND
        else:
            self.property_set["layout"] = chosen_layout
            for reg in dag.qregs.values():
                self.property_set["layout"].add_register(reg)

        self.property_set["VF2Layout_stop_reason"] = stop_reason
示例#4
0
    def run(self, dag):
        """run the layout method"""
        if self.coupling_map is None:
            raise TranspilerError("coupling_map or target must be specified.")
        if self.avg_error_map is None:
            self.avg_error_map = vf2_utils.build_average_error_map(
                self.target, self.properties, self.coupling_map)

        result = vf2_utils.build_interaction_graph(dag, self.strict_direction)
        if result is None:
            self.property_set[
                "VF2Layout_stop_reason"] = VF2LayoutStopReason.MORE_THAN_2Q
            return
        im_graph, im_graph_node_map, reverse_im_graph_node_map = result
        cm_graph, cm_nodes = vf2_utils.shuffle_coupling_graph(
            self.coupling_map, self.seed, self.strict_direction)
        # To avoid trying to over optimize the result by default limit the number
        # of trials based on the size of the graphs. For circuits with simple layouts
        # like an all 1q circuit we don't want to sit forever trying every possible
        # mapping in the search space if no other limits are set
        if self.max_trials is None and self.call_limit is None and self.time_limit is None:
            im_graph_edge_count = len(im_graph.edge_list())
            cm_graph_edge_count = len(self.coupling_map.graph.edge_list())
            self.max_trials = max(im_graph_edge_count,
                                  cm_graph_edge_count) + 15

        logger.debug("Running VF2 to find mappings")
        mappings = vf2_mapping(
            cm_graph,
            im_graph,
            subgraph=True,
            id_order=False,
            induced=False,
            call_limit=self.call_limit,
        )
        chosen_layout = None
        chosen_layout_score = None
        start_time = time.time()
        trials = 0
        for mapping in mappings:
            trials += 1
            logger.debug("Running trial: %s", trials)
            stop_reason = VF2LayoutStopReason.SOLUTION_FOUND
            layout = Layout({
                reverse_im_graph_node_map[im_i]: cm_nodes[cm_i]
                for cm_i, im_i in mapping.items()
            })
            # If the graphs have the same number of nodes we don't need to score or do multiple
            # trials as the score heuristic currently doesn't weigh nodes based on gates on a
            # qubit so the scores will always all be the same
            if len(cm_graph) == len(im_graph):
                chosen_layout = layout
                break
            layout_score = vf2_utils.score_layout(
                self.avg_error_map,
                layout,
                im_graph_node_map,
                reverse_im_graph_node_map,
                im_graph,
                self.strict_direction,
            )
            logger.debug("Trial %s has score %s", trials, layout_score)
            if chosen_layout is None:
                chosen_layout = layout
                chosen_layout_score = layout_score
            elif layout_score < chosen_layout_score:
                logger.debug(
                    "Found layout %s has a lower score (%s) than previous best %s (%s)",
                    layout,
                    layout_score,
                    chosen_layout,
                    chosen_layout_score,
                )
                chosen_layout = layout
                chosen_layout_score = layout_score
            if self.max_trials is not None and self.max_trials > 0 and trials >= self.max_trials:
                logger.debug("Trial %s is >= configured max trials %s", trials,
                             self.max_trials)
                break
            elapsed_time = time.time() - start_time
            if self.time_limit is not None and elapsed_time >= self.time_limit:
                logger.debug(
                    "VF2Layout has taken %s which exceeds configured max time: %s",
                    elapsed_time,
                    self.time_limit,
                )
                break
        if chosen_layout is None:
            stop_reason = VF2LayoutStopReason.NO_SOLUTION_FOUND
        else:
            self.property_set["layout"] = chosen_layout
            for reg in dag.qregs.values():
                self.property_set["layout"].add_register(reg)

        self.property_set["VF2Layout_stop_reason"] = stop_reason