def run(self, dag):

        # sorted to so that they are in the order they appear in the DAG
        # so ancestors/descendants makes sense
        barriers = [nd for nd in dag.topological_op_nodes() if nd.name == 'barrier']

        # get dict of barrier merges
        node_to_barrier_qubits = MergeAdjacentBarriers._collect_potential_merges(dag, barriers)

        if not node_to_barrier_qubits:
            return dag

        # add the merged barriers to a new DAG
        new_dag = DAGCircuit()

        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        # go over current nodes, and add them to the new dag
        for node in dag.topological_op_nodes():
            if node.name == 'barrier':
                if node in node_to_barrier_qubits:
                    qubits = node_to_barrier_qubits[node]
                    # qubits are stored as a set, need to convert to a list
                    new_dag.apply_operation_back(Barrier(len(qubits)), qargs=list(qubits))
            else:
                # copy the condition over too
                if node.condition:
                    new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs,
                                                 condition=node.condition)
                else:
                    new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs)
        return new_dag
    def create_updated_dag(self, layers, barriers):
        """
        Given a set of layers and barries, construct a new dag
        """
        new_dag = DAGCircuit()
        for qreg in self.dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in self.dag.cregs.values():
            new_dag.add_creg(creg)
        canonical_register = new_dag.qregs['q']
        for i, layer in enumerate(layers):
            curr_barriers = barriers[i]
            for b in curr_barriers:
                current_qregs = []
                for idx in b:
                    current_qregs.append(canonical_register[idx])
                new_dag.apply_operation_back(Barrier(len(b)), current_qregs,
                                             [])
            for triplet in layer:
                gate = triplet[0]
                new_dag.apply_operation_back(gate.op, gate.qargs, gate.cargs)

        for node in self.dag.op_nodes():
            if isinstance(node.op, Measure):
                new_dag.apply_operation_back(node.op, node.qargs, node.cargs)

        return new_dag
Пример #3
0
 def barrier(self, qubitlists):
     """Barrier instruction.
     """
     if self.listen:
         qubits = []
         for qubit in qubitlists:
             for j, _ in enumerate(qubit):
                 qubits.append(qubit[j])
     self.circuit.apply_operation_back(Barrier(qubits))
Пример #4
0
    def run(self, dag):
        """Run the BarrierBeforeFinalMeasurements pass on `dag`."""
        # Collect DAG nodes which are followed only by barriers or other measures.
        final_op_types = ['measure', 'barrier']
        final_ops = []
        for candidate_node in dag.named_nodes(*final_op_types):
            is_final_op = True

            for _, child_successors in dag.bfs_successors(candidate_node):

                if any(suc.type == 'op' and suc.name not in final_op_types
                       for suc in child_successors):
                    is_final_op = False
                    break

            if is_final_op:
                final_ops.append(candidate_node)

        if not final_ops:
            return dag

        # Create a layer with the barrier and add registers from the original dag.
        barrier_layer = DAGCircuit()
        for qreg in dag.qregs.values():
            barrier_layer.add_qreg(qreg)
        for creg in dag.cregs.values():
            barrier_layer.add_creg(creg)

        # Add a barrier across all qubits so swap mapper doesn't add a swap
        # from an unmeasured qubit after a measure.
        final_qubits = dag.qubits()

        barrier_layer.apply_operation_back(Barrier(len(final_qubits)),
                                           list(final_qubits), [])

        # Preserve order of final ops collected earlier from the original DAG.
        ordered_final_nodes = [
            node for node in dag.topological_op_nodes()
            if node in set(final_ops)
        ]

        # Move final ops to the new layer and append the new layer to the DAG.
        for final_node in ordered_final_nodes:
            barrier_layer.apply_operation_back(final_node.op, final_node.qargs,
                                               final_node.cargs)

        for final_op in final_ops:
            dag.remove_op_node(final_op)

        dag.compose(barrier_layer)

        # Merge the new barrier into any other barriers
        adjacent_pass = MergeAdjacentBarriers()
        return adjacent_pass.run(dag)
    def run(self, dag):
        """Return a circuit with a barrier before last measurments."""
        last_measures = []
        for measure in dag.get_named_nodes('measure'):
            is_last_measurement = all([
                after_measure in dag.output_map.values()
                for after_measure in dag.successors(measure)
            ])
            if is_last_measurement:
                last_measures.append(measure)

        if not last_measures:
            return dag

        # create a laywer with the barrier and the measurements in last_measures operation
        dag.add_basis_element('barrier', len(last_measures), 0, 0)
        barried_layer = DAGCircuit()
        last_measures_nodes = [
            dag.multi_graph.node[node] for node in last_measures
        ]
        last_measures_qubits = [
            node['qargs'][0] for node in last_measures_nodes
        ]

        # Add registers from the original dag.
        for qreg in dag.qregs.values():
            barried_layer.add_qreg(qreg)
        for creg in dag.cregs.values():
            barried_layer.add_creg(creg)

        # Add the barrier operation
        barried_layer.apply_operation_back(
            Barrier(qubits=last_measures_qubits))

        # Add the measurements to the behind the barrier
        for last_measures_node in last_measures_nodes:
            barried_layer.apply_operation_back(last_measures_node['op'])

        # Remove barriers in front the measurements in the original dag
        for last_measure in last_measures:
            for predecesor in dag.multi_graph.predecessors(last_measure):
                if dag.multi_graph.nodes[predecesor]['type'] == 'op' and \
                        isinstance(dag.multi_graph.nodes[predecesor]['op'], Barrier):
                    dag._remove_op_node(predecesor)

        # Remove the measurements from the original dag
        for last_measure in last_measures:
            dag._remove_op_node(last_measure)

        # Extend the original dag with the barried layer
        dag.extend_back(barried_layer)

        return dag
Пример #6
0
    def test_two_q_gates(self):
        """The method dag.twoQ_gates() returns all 2Q gate nodes"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(Barrier(2), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(Reset(), [self.qubit0], [])

        op_nodes = self.dag.twoQ_gates()
        self.assertEqual(len(op_nodes), 1)

        op_node = op_nodes.pop()
        self.assertIsInstance(op_node.op, Gate)
        self.assertEqual(len(op_node.qargs), 2)
Пример #7
0
    def test_two_q_gates(self):
        """The method dag.twoQ_gates() returns all 2Q gate nodes"""
        self.dag.apply_operation_back(HGate(self.qubit0))
        self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1))
        self.dag.apply_operation_back(Barrier((self.qubit0, self.qubit1)))
        self.dag.apply_operation_back(Reset(self.qubit0))

        op_nodes = self.dag.twoQ_gates()
        self.assertEqual(len(op_nodes), 1)

        op_node = op_nodes.pop()
        self.assertIsInstance(op_node["op"], Gate)
        self.assertEqual(len(op_node['qargs']), 2)
Пример #8
0
    def test_get_gates_nodes(self):
        """The method dag.gate_nodes() returns all gate nodes"""
        self.dag.apply_operation_back(HGate(self.qubit0))
        self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1))
        self.dag.apply_operation_back(Barrier((self.qubit0, self.qubit1)))
        self.dag.apply_operation_back(Reset(self.qubit0))

        op_nodes = self.dag.gate_nodes()
        self.assertEqual(len(op_nodes), 2)

        op_node_1 = op_nodes.pop()
        op_node_2 = op_nodes.pop()
        self.assertIsInstance(self.dag.node(op_node_1)["op"], Gate)
        self.assertIsInstance(self.dag.node(op_node_2)["op"], Gate)
Пример #9
0
    def _collect_potential_merges(dag, barriers):
        """Return the potential merges.

        Returns a dict of DAGNode : Barrier objects, where the barrier needs to be
        inserted where the corresponding DAGNode appears in the main DAG.
        """
        # if only got 1 or 0 barriers then can't merge
        if len(barriers) < 2:
            return None

        # mapping from the node that will be the main barrier to the
        # barrier object that gets built up
        node_to_barrier_qubits = {}

        # Start from the first barrier
        current_barrier = barriers[0]
        end_of_barrier = current_barrier
        current_barrier_nodes = [current_barrier]

        current_qubits = set(current_barrier.qargs)
        current_ancestors = dag.ancestors(current_barrier)
        current_descendants = dag.descendants(current_barrier)

        barrier_to_add = Barrier(len(current_qubits))

        for next_barrier in barriers[1:]:

            # Ensure barriers are adjacent before checking if they are mergeable.
            if dag._multi_graph.has_edge(end_of_barrier, next_barrier):

                # Remove all barriers that have already been included in this new barrier from the
                # set of ancestors/descendants as they will be removed from the new DAG when it is
                # created.
                next_ancestors = {
                    nd
                    for nd in dag.ancestors(next_barrier)
                    if nd not in current_barrier_nodes
                }
                next_descendants = {
                    nd
                    for nd in dag.descendants(next_barrier)
                    if nd not in current_barrier_nodes
                }
                next_qubits = set(next_barrier.qargs)

                if (not current_qubits.isdisjoint(next_qubits)
                        and current_ancestors.isdisjoint(next_descendants)
                        and current_descendants.isdisjoint(next_ancestors)):

                    # can be merged
                    current_ancestors = current_ancestors | next_ancestors
                    current_descendants = current_descendants | next_descendants
                    current_qubits = current_qubits | next_qubits

                    # update the barrier that will be added back to include this barrier
                    barrier_to_add = Barrier(len(current_qubits))

                    end_of_barrier = next_barrier
                    current_barrier_nodes.append(end_of_barrier)

                    continue

            # Fallback if barriers are not adjacent or not mergeable.

            # store the previously made barrier
            if barrier_to_add:
                node_to_barrier_qubits[end_of_barrier] = current_qubits

            # reset the properties
            current_qubits = set(next_barrier.qargs)
            current_ancestors = dag.ancestors(next_barrier)
            current_descendants = dag.descendants(next_barrier)

            barrier_to_add = Barrier(len(current_qubits))
            current_barrier_nodes = []

            end_of_barrier = next_barrier
            current_barrier_nodes.append(end_of_barrier)

        if barrier_to_add:
            node_to_barrier_qubits[end_of_barrier] = current_qubits

        return node_to_barrier_qubits
Пример #10
0
    def _process_node(self, node):
        """Carry out the action associated with a node."""
        if node.type == "program":
            self._process_children(node)

        elif node.type == "qreg":
            qreg = QuantumRegister(node.index, node.name)
            self.dag.add_qreg(qreg)

        elif node.type == "creg":
            creg = ClassicalRegister(node.index, node.name)
            self.dag.add_creg(creg)

        elif node.type == "id":
            raise QiskitError("internal error: _process_node on id")

        elif node.type == "int":
            raise QiskitError("internal error: _process_node on int")

        elif node.type == "real":
            raise QiskitError("internal error: _process_node on real")

        elif node.type == "indexed_id":
            raise QiskitError("internal error: _process_node on indexed_id")

        elif node.type == "id_list":
            # We process id_list nodes when they are leaves of barriers.
            return [
                self._process_bit_id(node_children)
                for node_children in node.children
            ]

        elif node.type == "primary_list":
            # We should only be called for a barrier.
            return [self._process_bit_id(m) for m in node.children]

        elif node.type == "gate":
            self._process_gate(node)

        elif node.type == "custom_unitary":
            self._process_custom_unitary(node)

        elif node.type == "universal_unitary":
            args = self._process_node(node.children[0])
            qid = self._process_bit_id(node.children[1])
            for element in qid:
                self.dag.apply_operation_back(UBase(*args, element),
                                              self.condition)

        elif node.type == "cnot":
            self._process_cnot(node)

        elif node.type == "expression_list":
            return node.children

        elif node.type == "binop":
            raise QiskitError("internal error: _process_node on binop")

        elif node.type == "prefix":
            raise QiskitError("internal error: _process_node on prefix")

        elif node.type == "measure":
            self._process_measure(node)

        elif node.type == "format":
            self.version = node.version()

        elif node.type == "barrier":
            ids = self._process_node(node.children[0])
            qubits = []
            for qubit in ids:
                for j, _ in enumerate(qubit):
                    qubits.append(qubit[j])
            self.dag.apply_operation_back(Barrier(len(qubits)), qubits, [])

        elif node.type == "reset":
            id0 = self._process_bit_id(node.children[0])
            for i, _ in enumerate(id0):
                self.dag.apply_operation_back(Reset(), [id0[i]], [],
                                              self.condition)

        elif node.type == "if":
            self._process_if(node)

        elif node.type == "opaque":
            self._process_gate(node, opaque=True)

        elif node.type == "external":
            raise QiskitError("internal error: _process_node on external")

        else:
            raise QiskitError("internal error: undefined node type", node.type,
                              "line=%s" % node.line, "file=%s" % node.file)
        return None
    def run(self, dag):
        """Return a circuit with a barrier before last measurments."""

        # Collect DAG nodes which are followed only by barriers or other measures.
        final_op_types = ['measure', 'barrier']
        final_ops = []
        for candidate_op in dag.named_nodes(*final_op_types):
            is_final_op = True
            for _, child_successors in dag.bfs_successors(candidate_op):
                if any(
                        dag.node(suc)['type'] == 'op'
                        and dag.node(suc)['op'].name not in final_op_types
                        for suc in child_successors):
                    is_final_op = False
                    break

            if is_final_op:
                final_ops.append(candidate_op)

        if not final_ops:
            return dag

        # Create a layer with the barrier and add registers from the original dag.
        barrier_layer = DAGCircuit()
        for qreg in dag.qregs.values():
            barrier_layer.add_qreg(qreg)
        for creg in dag.cregs.values():
            barrier_layer.add_creg(creg)

        final_qubits = set(
            dag.node(final_op)['qargs'][0] for final_op in final_ops)

        new_barrier_id = barrier_layer.apply_operation_back(
            Barrier(qubits=final_qubits))

        # Preserve order of final ops collected earlier from the original DAG.
        ordered_node_ids = [
            node_id for node_id in dag.node_nums_in_topological_order()
            if node_id in set(final_ops)
        ]
        ordered_final_nodes = [dag.node(node) for node in ordered_node_ids]

        # Move final ops to the new layer and append the new layer to the DAG.
        for final_node in ordered_final_nodes:
            barrier_layer.apply_operation_back(final_node['op'])

        for final_op in final_ops:
            dag._remove_op_node(final_op)

        # Check to see if the new barrier added to the DAG is equivalent to any
        # existing barriers, and if so, consolidate the two.
        our_ancestors = barrier_layer.ancestors(new_barrier_id)
        our_descendants = barrier_layer.descendants(new_barrier_id)
        our_qubits = final_qubits

        existing_barriers = barrier_layer.named_nodes('barrier')
        existing_barriers.remove(new_barrier_id)

        for candidate_barrier in existing_barriers:
            their_ancestors = barrier_layer.ancestors(candidate_barrier)
            their_descendants = barrier_layer.descendants(candidate_barrier)
            their_qubits = set(
                barrier_layer.node(candidate_barrier)['op'].qargs)

            if (not our_qubits.isdisjoint(their_qubits)
                    and our_ancestors.isdisjoint(their_descendants)
                    and our_descendants.isdisjoint(their_ancestors)):
                merge_barrier = Barrier(qubits=(our_qubits | their_qubits))
                merge_barrier_id = barrier_layer.apply_operation_front(
                    merge_barrier)

                our_ancestors = our_ancestors | their_ancestors
                our_descendants = our_descendants | their_descendants

                barrier_layer._remove_op_node(candidate_barrier)
                barrier_layer._remove_op_node(new_barrier_id)

                new_barrier_id = merge_barrier_id

        dag.extend_back(barrier_layer)

        return dag
Пример #12
0
    def run(self, dag):
        """Return a circuit with a barrier before last measurments."""

        # Collect DAG nodes which are followed only by barriers or other measures.
        final_op_types = ['measure', 'barrier']
        final_ops = []
        for candidate_node in dag.named_nodes(*final_op_types):
            is_final_op = True

            for _, child_successors in dag.bfs_successors(candidate_node):

                if any(suc.type == 'op' and suc.name not in final_op_types
                       for suc in child_successors):
                    is_final_op = False
                    break

            if is_final_op:
                final_ops.append(candidate_node)

        if not final_ops:
            return dag

        # Create a layer with the barrier and add registers from the original dag.
        barrier_layer = DAGCircuit()
        for qreg in dag.qregs.values():
            barrier_layer.add_qreg(qreg)
        for creg in dag.cregs.values():
            barrier_layer.add_creg(creg)

        final_qubits = set(final_op.qargs[0] for final_op in final_ops)

        new_barrier_node = barrier_layer.apply_operation_back(
            Barrier(len(final_qubits)), list(final_qubits), [])

        # Preserve order of final ops collected earlier from the original DAG.
        ordered_final_nodes = [node for node in dag.nodes_in_topological_order()
                               if node in set(final_ops)]

        # Move final ops to the new layer and append the new layer to the DAG.
        for final_node in ordered_final_nodes:
            barrier_layer.apply_operation_back(final_node.op,
                                               final_node.qargs,
                                               final_node.cargs)

        for final_op in final_ops:
            dag.remove_op_node(final_op)

        # Check to see if the new barrier added to the DAG is equivalent to any
        # existing barriers, and if so, consolidate the two.
        our_ancestors = barrier_layer.ancestors(new_barrier_node)
        our_descendants = barrier_layer.descendants(new_barrier_node)
        our_qubits = final_qubits

        existing_barriers = sorted(barrier_layer.named_nodes('barrier'))
        # remove element from the list
        for i, node in enumerate(existing_barriers):
            if node == new_barrier_node:
                del existing_barriers[i]
                break

        for candidate_barrier in existing_barriers:
            their_ancestors = barrier_layer.ancestors(candidate_barrier)
            their_descendants = barrier_layer.descendants(candidate_barrier)
            their_qubits = set(candidate_barrier.qargs)

            if (
                    not our_qubits.isdisjoint(their_qubits)
                    and our_ancestors.isdisjoint(their_descendants)
                    and our_descendants.isdisjoint(their_ancestors)
            ):
                merge_barrier_qubits = (our_qubits | their_qubits)
                merge_barrier_node = barrier_layer.apply_operation_front(
                    Barrier(len(merge_barrier_qubits)), merge_barrier_qubits, [])

                our_ancestors = our_ancestors | their_ancestors
                our_descendants = our_descendants | their_descendants

                barrier_layer.remove_op_node(candidate_barrier)
                barrier_layer.remove_op_node(new_barrier_node)

                new_barrier_node = merge_barrier_node

        dag.extend_back(barrier_layer)

        return dag