Пример #1
0
class TestDagApplyOperation(QiskitTestCase):
    """Test adding an op node to a dag."""
    def setUp(self):
        self.dag = DAGCircuit()
        qreg = QuantumRegister(3, 'qr')
        creg = ClassicalRegister(2, 'cr')
        self.dag.add_qreg(qreg)
        self.dag.add_creg(creg)

        self.qubit0 = qreg[0]
        self.qubit1 = qreg[1]
        self.qubit2 = qreg[2]
        self.clbit0 = creg[0]
        self.clbit1 = creg[1]
        self.condition = (creg, 3)

    def test_apply_operation_back(self):
        """The apply_operation_back() method."""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [],
                                      condition=None)
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [],
                                      condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1],
                                      [],
                                      condition=None)
        self.dag.apply_operation_back(XGate(), [self.qubit1], [],
                                      condition=self.condition)
        self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0],
                                      [],
                                      condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1],
                                      [],
                                      condition=None)
        self.assertEqual(len(list(self.dag.nodes())), 16)
        self.assertEqual(len(list(self.dag.edges())), 17)

    def test_edges(self):
        """Test that DAGCircuit.edges() behaves as expected with ops."""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [],
                                      condition=None)
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [],
                                      condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1],
                                      [],
                                      condition=None)
        self.dag.apply_operation_back(XGate(), [self.qubit1], [],
                                      condition=self.condition)
        self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0],
                                      [],
                                      condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1],
                                      [],
                                      condition=None)
        out_edges = self.dag.edges(self.dag.output_map.values())
        self.assertEqual(list(out_edges), [])
        in_edges = self.dag.edges(self.dag.input_map.values())
        # number of edges for input nodes should be the same as number of wires
        self.assertEqual(len(list(in_edges)), 5)

    def test_apply_operation_back_conditional(self):
        """Test consistency of apply_operation_back with condition set."""

        # Single qubit gate conditional: qc.h(qr[2]).c_if(cr, 3)

        h_gate = HGate()
        h_gate.condition = self.condition
        h_node = self.dag.apply_operation_back(h_gate, [self.qubit2], [],
                                               h_gate.condition)

        self.assertEqual(h_node.qargs, [self.qubit2])
        self.assertEqual(h_node.cargs, [])
        self.assertEqual(h_node.condition, h_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(h_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit2]._node_id, h_node._node_id, {
                    'wire': self.qubit2,
                    'name': 'qr[2]'
                }),
                (self.dag.input_map[self.clbit0]._node_id, h_node._node_id, {
                    'wire': self.clbit0,
                    'name': 'cr[0]'
                }),
                (self.dag.input_map[self.clbit1]._node_id, h_node._node_id, {
                    'wire': self.clbit1,
                    'name': 'cr[1]'
                }),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(h_node._node_id)),
            sorted([
                (h_node._node_id, self.dag.output_map[self.qubit2]._node_id, {
                    'wire': self.qubit2,
                    'name': 'qr[2]'
                }),
                (h_node._node_id, self.dag.output_map[self.clbit0]._node_id, {
                    'wire': self.clbit0,
                    'name': 'cr[0]'
                }),
                (h_node._node_id, self.dag.output_map[self.clbit1]._node_id, {
                    'wire': self.clbit1,
                    'name': 'cr[1]'
                }),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(
                self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(
                self.dag._multi_graph))

    def test_apply_operation_back_conditional_measure(self):
        """Test consistency of apply_operation_back for conditional measure."""

        # Measure targeting a clbit which is not a member of the conditional
        # register. qc.measure(qr[0], cr[0]).c_if(cr2, 0)

        new_creg = ClassicalRegister(1, 'cr2')
        self.dag.add_creg(new_creg)

        meas_gate = Measure()
        meas_gate.condition = (new_creg, 0)
        meas_node = self.dag.apply_operation_back(meas_gate, [self.qubit0],
                                                  [self.clbit0],
                                                  meas_gate.condition)

        self.assertEqual(meas_node.qargs, [self.qubit0])
        self.assertEqual(meas_node.cargs, [self.clbit0])
        self.assertEqual(meas_node.condition, meas_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(meas_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit0]._node_id, meas_node._node_id,
                 {
                     'wire': self.qubit0,
                     'name': 'qr[0]'
                 }),
                (self.dag.input_map[self.clbit0]._node_id, meas_node._node_id,
                 {
                     'wire': self.clbit0,
                     'name': 'cr[0]'
                 }),
                (self.dag.input_map[new_creg[0]]._node_id, meas_node._node_id,
                 {
                     'wire': Clbit(new_creg, 0),
                     'name': 'cr2[0]'
                 }),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(meas_node._node_id)),
            sorted([
                (meas_node._node_id, self.dag.output_map[self.qubit0]._node_id,
                 {
                     'wire': self.qubit0,
                     'name': 'qr[0]'
                 }),
                (meas_node._node_id, self.dag.output_map[self.clbit0]._node_id,
                 {
                     'wire': self.clbit0,
                     'name': 'cr[0]'
                 }),
                (meas_node._node_id, self.dag.output_map[new_creg[0]]._node_id,
                 {
                     'wire': Clbit(new_creg, 0),
                     'name': 'cr2[0]'
                 }),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(
                self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(
                self.dag._multi_graph))

    def test_apply_operation_back_conditional_measure_to_self(self):
        """Test consistency of apply_operation_back for measure onto conditioning bit."""

        # Measure targeting a clbit which _is_ a member of the conditional
        # register. qc.measure(qr[0], cr[0]).c_if(cr, 3)

        meas_gate = Measure()
        meas_gate.condition = self.condition
        meas_node = self.dag.apply_operation_back(meas_gate, [self.qubit1],
                                                  [self.clbit1],
                                                  self.condition)

        self.assertEqual(meas_node.qargs, [self.qubit1])
        self.assertEqual(meas_node.cargs, [self.clbit1])
        self.assertEqual(meas_node.condition, meas_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(meas_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit1]._node_id, meas_node._node_id,
                 {
                     'wire': self.qubit1,
                     'name': 'qr[1]'
                 }),
                (self.dag.input_map[self.clbit0]._node_id, meas_node._node_id,
                 {
                     'wire': self.clbit0,
                     'name': 'cr[0]'
                 }),
                (self.dag.input_map[self.clbit1]._node_id, meas_node._node_id,
                 {
                     'wire': self.clbit1,
                     'name': 'cr[1]'
                 }),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(meas_node._node_id)),
            sorted([
                (meas_node._node_id, self.dag.output_map[self.qubit1]._node_id,
                 {
                     'wire': self.qubit1,
                     'name': 'qr[1]'
                 }),
                (meas_node._node_id, self.dag.output_map[self.clbit0]._node_id,
                 {
                     'wire': self.clbit0,
                     'name': 'cr[0]'
                 }),
                (meas_node._node_id, self.dag.output_map[self.clbit1]._node_id,
                 {
                     'wire': self.clbit1,
                     'name': 'cr[1]'
                 }),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(
                self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(
                self.dag._multi_graph))

    def test_apply_operation_front(self):
        """The apply_operation_front() method"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_front(Reset(), [self.qubit0], [])
        h_node = self.dag.op_nodes(op=HGate).pop()
        reset_node = self.dag.op_nodes(op=Reset).pop()

        self.assertIn(reset_node, set(self.dag.predecessors(h_node)))
Пример #2
0
class TestDagOperations(QiskitTestCase):
    """Test ops inside the dag"""

    def setUp(self):
        self.dag = DAGCircuit()
        qreg = QuantumRegister(3, 'qr')
        creg = ClassicalRegister(2, 'cr')
        self.dag.add_qreg(qreg)
        self.dag.add_creg(creg)

        self.qubit0 = qreg[0]
        self.qubit1 = qreg[1]
        self.qubit2 = qreg[2]
        self.clbit0 = creg[0]
        self.clbit1 = creg[1]
        self.condition = (creg, 3)

    def test_apply_operation_back(self):
        """The apply_operation_back() method."""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [], condition=None)
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [], condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None)
        self.dag.apply_operation_back(XGate(), [self.qubit1], [], condition=self.condition)
        self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], [], condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None)
        self.assertEqual(len(list(self.dag.nodes())), 16)
        self.assertEqual(len(list(self.dag.edges())), 17)

    def test_edges(self):
        """Test that DAGCircuit.edges() behaves as expected with ops."""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [], condition=None)
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [], condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None)
        self.dag.apply_operation_back(XGate(), [self.qubit1], [], condition=self.condition)
        self.dag.apply_operation_back(Measure(), [self.qubit0, self.clbit0], [], condition=None)
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [], condition=None)
        out_edges = self.dag.edges(self.dag.output_map.values())
        self.assertEqual(list(out_edges), [])
        in_edges = self.dag.edges(self.dag.input_map.values())
        # number of edges for input nodes should be the same as number of wires
        self.assertEqual(len(list(in_edges)), 5)

    def test_apply_operation_back_conditional(self):
        """Test consistency of apply_operation_back with condition set."""

        # Single qubit gate conditional: qc.h(qr[2]).c_if(cr, 3)

        h_gate = HGate()
        h_gate.condition = self.condition
        h_node = self.dag.apply_operation_back(
            h_gate, [self.qubit2], [], h_gate.condition)

        self.assertEqual(h_node.qargs, [self.qubit2])
        self.assertEqual(h_node.cargs, [])
        self.assertEqual(h_node.condition, h_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(h_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit2]._node_id, h_node._node_id,
                 {'wire': self.qubit2, 'name': 'qr[2]'}),
                (self.dag.input_map[self.clbit0]._node_id, h_node._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (self.dag.input_map[self.clbit1]._node_id, h_node._node_id,
                 {'wire': self.clbit1, 'name': 'cr[1]'}),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(h_node._node_id)),
            sorted([
                (h_node._node_id, self.dag.output_map[self.qubit2]._node_id,
                 {'wire': self.qubit2, 'name': 'qr[2]'}),
                (h_node._node_id, self.dag.output_map[self.clbit0]._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (h_node._node_id, self.dag.output_map[self.clbit1]._node_id,
                 {'wire': self.clbit1, 'name': 'cr[1]'}),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(self.dag._multi_graph))

    def test_apply_operation_back_conditional_measure(self):
        """Test consistency of apply_operation_back for conditional measure."""

        # Measure targeting a clbit which is not a member of the conditional
        # register. qc.measure(qr[0], cr[0]).c_if(cr2, 0)

        new_creg = ClassicalRegister(1, 'cr2')
        self.dag.add_creg(new_creg)

        meas_gate = Measure()
        meas_gate.condition = (new_creg, 0)
        meas_node = self.dag.apply_operation_back(
            meas_gate, [self.qubit0], [self.clbit0], meas_gate.condition)

        self.assertEqual(meas_node.qargs, [self.qubit0])
        self.assertEqual(meas_node.cargs, [self.clbit0])
        self.assertEqual(meas_node.condition, meas_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(meas_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit0]._node_id, meas_node._node_id,
                 {'wire': self.qubit0, 'name': 'qr[0]'}),
                (self.dag.input_map[self.clbit0]._node_id, meas_node._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (self.dag.input_map[new_creg[0]]._node_id, meas_node._node_id,
                 {'wire': Clbit(new_creg, 0), 'name': 'cr2[0]'}),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(meas_node._node_id)),
            sorted([
                (meas_node._node_id, self.dag.output_map[self.qubit0]._node_id,
                 {'wire': self.qubit0, 'name': 'qr[0]'}),
                (meas_node._node_id, self.dag.output_map[self.clbit0]._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (meas_node._node_id, self.dag.output_map[new_creg[0]]._node_id,
                 {'wire': Clbit(new_creg, 0), 'name': 'cr2[0]'}),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(self.dag._multi_graph))

    def test_apply_operation_back_conditional_measure_to_self(self):
        """Test consistency of apply_operation_back for measure onto conditioning bit."""

        # Measure targeting a clbit which _is_ a member of the conditional
        # register. qc.measure(qr[0], cr[0]).c_if(cr, 3)

        meas_gate = Measure()
        meas_gate.condition = self.condition
        meas_node = self.dag.apply_operation_back(
            meas_gate, [self.qubit1], [self.clbit1], self.condition)

        self.assertEqual(meas_node.qargs, [self.qubit1])
        self.assertEqual(meas_node.cargs, [self.clbit1])
        self.assertEqual(meas_node.condition, meas_gate.condition)

        self.assertEqual(
            sorted(self.dag._get_multi_graph_in_edges(meas_node._node_id)),
            sorted([
                (self.dag.input_map[self.qubit1]._node_id, meas_node._node_id,
                 {'wire': self.qubit1, 'name': 'qr[1]'}),
                (self.dag.input_map[self.clbit0]._node_id, meas_node._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (self.dag.input_map[self.clbit1]._node_id, meas_node._node_id,
                 {'wire': self.clbit1, 'name': 'cr[1]'}),
            ]))

        self.assertEqual(
            sorted(self.dag._get_multi_graph_out_edges(meas_node._node_id)),
            sorted([
                (meas_node._node_id, self.dag.output_map[self.qubit1]._node_id,
                 {'wire': self.qubit1, 'name': 'qr[1]'}),
                (meas_node._node_id, self.dag.output_map[self.clbit0]._node_id,
                 {'wire': self.clbit0, 'name': 'cr[0]'}),
                (meas_node._node_id, self.dag.output_map[self.clbit1]._node_id,
                 {'wire': self.clbit1, 'name': 'cr[1]'}),
            ]))

        if self.dag._USE_RX:
            self.assertTrue(rx.is_directed_acyclic_graph(self.dag._multi_graph))
        else:
            self.assertTrue(nx.is_directed_acyclic_graph(self.dag._multi_graph))

    def test_apply_operation_front(self):
        """The apply_operation_front() method"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_front(Reset(), [self.qubit0], [])
        h_node = self.dag.op_nodes(op=HGate).pop()
        reset_node = self.dag.op_nodes(op=Reset).pop()

        self.assertIn(reset_node, set(self.dag.predecessors(h_node)))

    def test_get_op_nodes_all(self):
        """The method dag.op_nodes() returns all op nodes"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(Reset(), [self.qubit0], [])

        op_nodes = self.dag.op_nodes()
        self.assertEqual(len(op_nodes), 3)

        for node in op_nodes:
            self.assertIsInstance(node.op, Instruction)

    def test_get_op_nodes_particular(self):
        """The method dag.gates_nodes(op=AGate) returns all the AGate nodes"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(HGate(), [self.qubit1], [])
        self.dag.apply_operation_back(Reset(), [self.qubit0], [])

        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])

        op_nodes = self.dag.op_nodes(op=HGate)
        self.assertEqual(len(op_nodes), 2)

        op_node_1 = op_nodes.pop()
        op_node_2 = op_nodes.pop()

        self.assertIsInstance(op_node_1.op, HGate)
        self.assertIsInstance(op_node_2.op, HGate)

    def test_quantum_successors(self):
        """The method dag.quantum_successors() returns successors connected by quantum edges"""

        # q_0: |0>─────■───|0>─
        #         ┌─┐┌─┴─┐
        # q_1: |0>┤M├┤ X ├─────
        #         └╥┘└───┘
        #  c_0: 0 ═╬═══════════
        #          ║
        #  c_1: 0 ═╩═══════════

        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(Reset(), [self.qubit0], [])

        successor_measure = self.dag.quantum_successors(
            self.dag.named_nodes('measure').pop())
        cnot_node = next(successor_measure)
        with self.assertRaises(StopIteration):
            next(successor_measure)

        self.assertIsInstance(cnot_node.op, CXGate)

        successor_cnot = self.dag.quantum_successors(cnot_node)
        # Ordering between Reset and out[q1] is indeterminant.

        successor1 = next(successor_cnot)
        successor2 = next(successor_cnot)
        with self.assertRaises(StopIteration):
            next(successor_cnot)

        self.assertTrue(
            (successor1.type == 'out' and isinstance(successor2.op, Reset))
            or (successor2.type == 'out' and isinstance(successor1.op, Reset))
        )

    def test_quantum_predecessors(self):
        """The method dag.quantum_predecessors() returns predecessors connected by quantum edges"""

        # q_0: |0>─|0>───■─────
        #              ┌─┴─┐┌─┐
        # q_1: |0>─────┤ X ├┤M├
        #              └───┘└╥┘
        #  c_0: 0 ═══════════╬═
        #                    ║
        #  c_1: 0 ═══════════╩═

        self.dag.apply_operation_back(Reset(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [])

        predecessor_measure = self.dag.quantum_predecessors(
            self.dag.named_nodes('measure').pop())
        cnot_node = next(predecessor_measure)
        with self.assertRaises(StopIteration):
            next(predecessor_measure)

        self.assertIsInstance(cnot_node.op, CXGate)

        predecessor_cnot = self.dag.quantum_predecessors(cnot_node)
        # Ordering between Reset and in[q1] is indeterminant.

        predecessor1 = next(predecessor_cnot)
        predecessor2 = next(predecessor_cnot)
        with self.assertRaises(StopIteration):
            next(predecessor_cnot)

        self.assertTrue(
            (predecessor1.type == 'in' and isinstance(predecessor2.op, Reset))
            or (predecessor2.type == 'in' and isinstance(predecessor1.op, Reset))
        )

    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(CXGate(), [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(op_node_1.op, Gate)
        self.assertIsInstance(op_node_2.op, Gate)

    def test_two_q_gates(self):
        """The method dag.two_qubit_ops() returns all 2Q gate operation nodes"""
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [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.two_qubit_ops()
        self.assertEqual(len(op_nodes), 1)

        op_node = op_nodes.pop()
        self.assertIsInstance(op_node.op, Gate)
        self.assertEqual(len(op_node.qargs), 2)

    def test_get_named_nodes(self):
        """The get_named_nodes(AName) method returns all the nodes with name AName"""
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2], [])
        self.dag.apply_operation_back(HGate(), [self.qubit2], [])

        # The ordering is not assured, so we only compare the output (unordered) sets.
        # We use tuples because lists aren't hashable.
        named_nodes = self.dag.named_nodes('cx')

        node_qargs = {tuple(node.qargs)
                      for node in named_nodes}

        expected_qargs = {
            (self.qubit0, self.qubit1),
            (self.qubit2, self.qubit1),
            (self.qubit0, self.qubit2)}
        self.assertEqual(expected_qargs, node_qargs)

    def test_topological_nodes(self):
        """The topological_nodes() method"""
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2], [])
        self.dag.apply_operation_back(HGate(), [self.qubit2], [])

        named_nodes = self.dag.topological_nodes()

        expected = [('qr[0]', []),
                    ('qr[1]', []),
                    ('cx', [self.qubit0, self.qubit1]),
                    ('h', [self.qubit0]),
                    ('qr[2]', []),
                    ('cx', [self.qubit2, self.qubit1]),
                    ('cx', [self.qubit0, self.qubit2]),
                    ('h', [self.qubit2]),
                    ('qr[0]', []),
                    ('qr[1]', []),
                    ('qr[2]', []),
                    ('cr[0]', []),
                    ('cr[0]', []),
                    ('cr[1]', []),
                    ('cr[1]', [])]
        self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes])

    def test_topological_op_nodes(self):
        """The topological_op_nodes() method"""
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2], [])
        self.dag.apply_operation_back(HGate(), [self.qubit2], [])

        named_nodes = self.dag.topological_op_nodes()

        expected = [('cx', [self.qubit0, self.qubit1]),
                    ('h', [self.qubit0]),
                    ('cx', [self.qubit2, self.qubit1]),
                    ('cx', [self.qubit0, self.qubit2]),
                    ('h', [self.qubit2])]
        self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes])

    def test_dag_nodes_on_wire(self):
        """Test that listing the gates on a qubit/classical bit gets the correct gates"""
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(HGate(), [self.qubit0], [])

        qbit = self.dag.qubits()[0]
        self.assertEqual([0, 10, 11, 1], [i._node_id for i in self.dag.nodes_on_wire(qbit)])
        self.assertEqual([10, 11],
                         [i._node_id for i in self.dag.nodes_on_wire(qbit, only_ops=True)])

        cbit = self.dag.clbits()[0]
        self.assertEqual([6, 7], [i._node_id for i in self.dag.nodes_on_wire(cbit)])
        self.assertEqual([], [i._node_id for i in self.dag.nodes_on_wire(cbit, only_ops=True)])

        with self.assertRaises(DAGCircuitError):
            next(self.dag.nodes_on_wire((qbit.register, 7)))

    def test_dag_nodes_on_wire_multiple_successors(self):
        """
        Test that if a DAGNode has multiple successors in the DAG along one wire, they are all
        retrieved in order. This could be the case for a circuit such as

                q0_0: |0>──■─────────■──
                         ┌─┴─┐┌───┐┌─┴─┐
                q0_1: |0>┤ X ├┤ H ├┤ X ├
                         └───┘└───┘└───┘
        Both the 2nd CX gate and the H gate follow the first CX gate in the DAG, so they
        both must be returned but in the correct order.
        """
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])
        self.dag.apply_operation_back(HGate(), [self.qubit1], [])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], [])

        nodes = self.dag.nodes_on_wire(self.dag.qubits()[1], only_ops=True)
        node_names = [nd.name for nd in nodes]

        self.assertEqual(node_names, ['cx', 'h', 'cx'])

    def test_remove_op_node(self):
        """Test remove_op_node method."""
        self.dag.apply_operation_back(HGate(), [self.qubit0])

        op_nodes = self.dag.gate_nodes()
        h_gate = op_nodes.pop()
        self.dag.remove_op_node(h_gate)

        self.assertEqual(len(self.dag.gate_nodes()), 0)

    def test_remove_op_node_longer(self):
        """Test remove_op_node method in a "longer" dag"""
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1])
        self.dag.apply_operation_back(HGate(), [self.qubit0])
        self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1])
        self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit2])
        self.dag.apply_operation_back(HGate(), [self.qubit2])

        op_nodes = list(self.dag.topological_op_nodes())
        self.dag.remove_op_node(op_nodes[0])

        expected = [('h', [self.qubit0]),
                    ('cx', [self.qubit2, self.qubit1]),
                    ('cx', [self.qubit0, self.qubit2]),
                    ('h', [self.qubit2])]
        self.assertEqual(expected,
                         [(i.name, i.qargs) for i in self.dag.topological_op_nodes()])

    def test_remove_non_op_node(self):
        """Try to remove a non-op node with remove_op_node method."""
        self.dag.apply_operation_back(HGate(), [self.qubit0])

        in_node = next(self.dag.topological_nodes())
        self.assertRaises(DAGCircuitError, self.dag.remove_op_node, in_node)

    def test_dag_collect_runs(self):
        """Test the collect_runs method with 3 different gates."""
        self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0])
        self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0])
        self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0])
        self.dag.apply_operation_back(CXGate(), [self.qubit2, self.qubit1])
        self.dag.apply_operation_back(CXGate(), [self.qubit1, self.qubit2])
        self.dag.apply_operation_back(HGate(), [self.qubit2])
        collected_runs = self.dag.collect_runs(['u1', 'cx', 'h'])
        self.assertEqual(len(collected_runs), 3)
        for run in collected_runs:
            if run[0].name == 'cx':
                self.assertEqual(len(run), 2)
                self.assertEqual(['cx'] * 2, [x.name for x in run])
                self.assertEqual(
                    [[self.qubit2, self.qubit1], [self.qubit1, self.qubit2]],
                    [x.qargs for x in run])
            elif run[0].name == 'h':
                self.assertEqual(len(run), 1)
                self.assertEqual(['h'], [x.name for x in run])
                self.assertEqual([[self.qubit2]], [x.qargs for x in run])
            elif run[0].name == 'u1':
                self.assertEqual(len(run), 3)
                self.assertEqual(['u1'] * 3, [x.name for x in run])
                self.assertEqual(
                    [[self.qubit0], [self.qubit0], [self.qubit0]],
                    [x.qargs for x in run])
            else:
                self.fail('Unknown run encountered')

    def test_dag_collect_runs_start_with_conditional(self):
        """Test collect runs with a conditional at the start of the run."""
        self.dag.apply_operation_back(
            HGate(), [self.qubit0], condition=self.condition)
        self.dag.apply_operation_back(HGate(), [self.qubit0])
        self.dag.apply_operation_back(HGate(), [self.qubit0])
        collected_runs = self.dag.collect_runs(['h'])
        self.assertEqual(len(collected_runs), 1)
        run = collected_runs.pop()
        self.assertEqual(len(run), 2)
        self.assertEqual(['h', 'h'], [x.name for x in run])
        self.assertEqual([[self.qubit0], [self.qubit0]],
                         [x.qargs for x in run])

    def test_dag_collect_runs_conditional_in_middle(self):
        """Test collect_runs with a conditional in the middle of a run."""
        self.dag.apply_operation_back(HGate(), [self.qubit0])
        self.dag.apply_operation_back(
            HGate(), [self.qubit0], condition=self.condition)
        self.dag.apply_operation_back(HGate(), [self.qubit0])
        collected_runs = self.dag.collect_runs(['h'])
        # Should return 2 single h gate runs (1 before condition, 1 after)
        self.assertEqual(len(collected_runs), 2)
        for run in collected_runs:
            self.assertEqual(len(run), 1)
            self.assertEqual(['h'], [x.name for x in run])
            self.assertEqual([[self.qubit0]], [x.qargs for x in run])