Repository: Qiskit/qiskit

Issue:
DAGCircuit Documentation types outdated
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information
The documentation of DAGCircuit still references tuples instead of the QuantumRegisters as input type for wires and qargs. This does not work any more.

- **Qiskit Terra version**: 0.8.2
- **Python version**: 3.7.4
- **Operating system**: macOS 10.14

### What is the current behavior?
An excerpt from the current documentation:
```
    def apply_operation_back(self, op, qargs=None, cargs=None, condition=None):
        """Apply an operation to the output of the circuit.

        Args:
            op (Instruction): the operation associated with the DAG node
            qargs (list[tuple]): qubits that op will be applied to
            cargs (list[tuple]): cbits that op will be applied to
            condition (tuple or None): optional condition (ClassicalRegister, int)

        Returns:
            DAGNode: the current max node

        Raises:
            DAGCircuitError: if a leaf node is connected to multiple outputs

        """
```
which lists tuples as expected type.




Discussion:
I just took a look at the current master docstring for `apply_operation_back()` and it is correctly listing the input type as a list of Qubit objects and Clbit objects: https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/dagcircuit/dagcircuit.py#L239-L254 @eddieschoute what do you think we need here? We can update the docstring to include more exposition on the docstring to try and make it clearer (it's a bit terse now). But nothing there looks wrong to me.

If it's just a matter of the [hosted documentation](https://qiskit.org/documentation/autodoc/qiskit.dagcircuit.dagcircuit.html) and pip release not being up to date, that will get corrected automatically after we release 0.9 with the bit classes. They didn't exist in 0.8.x so the published documentation is correct for the released version.
I checked out the latest version and you're right about `apply_operation_back`, however, `apply_operation_front` still has the old description, see https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/dagcircuit/dagcircuit.py#L285.
It also looks like `compose_back` still uses the old language, see https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/dagcircuit/dagcircuit.py#L437. I suspect this should be qubits or quantum registers that are being connected by edge_map.
Sorry for the slow response. On taking another look at this the `edge_map` case is actually a bit weird. Looking at the code which actually consumes the argument `_check_edgemap_registers()` and `_check_wiremap_validity()` in It looks like the key is still a tuple of `(register, index)` (although they can be bit classes too because the access patterns from tuples were preserved with deprecated functions on the new classes) but the values are the bit classes (either Qubit or Clbit). I'll update the docs for both `compose_back()` and `apply_operation_front()` shortly.

Resolving patch:
diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py
--- a/qiskit/dagcircuit/dagcircuit.py
+++ b/qiskit/dagcircuit/dagcircuit.py
@@ -190,7 +190,7 @@ def _check_bits(self, args, amap):
 
         Args:
             args (list): (register,idx) tuples
-            amap (dict): a dictionary keyed on (register,idx) tuples
+            amap (dict): a dictionary keyed on bit objects
 
         Raises:
             DAGCircuitError: if a qubit is not contained in amap
@@ -199,7 +199,7 @@ def _check_bits(self, args, amap):
         for wire in args:
             if wire not in amap:
                 raise DAGCircuitError("(qu)bit %s[%d] not found" %
-                                      (wire[0].name, wire[1]))
+                                      (wire.register.name, wire.index))
 
     def _bits_in_condition(self, cond):
         """Return a list of bits in the given condition.
@@ -287,8 +287,8 @@ def apply_operation_front(self, op, qargs, cargs, condition=None):
 
         Args:
             op (Instruction): the operation associated with the DAG node
-            qargs (list[tuple]): qubits that op will be applied to
-            cargs (list[tuple]): cbits that op will be applied to
+            qargs (list[Qubit]): Qubits that op will be applied to
+            cargs (list[Clbit]): Clbits that op will be applied to
             condition (tuple or None): optional condition (ClassicalRegister, value)
 
         Returns:
@@ -442,9 +442,10 @@ def compose_back(self, input_circuit, edge_map=None):
 
         Args:
             input_circuit (DAGCircuit): circuit to append
-            edge_map (dict): map {(Register, int): (Register, int)}
-                from the output wires of input_circuit to input wires
-                of self.
+            edge_map (dict): map {Bit: Bit} from the output wires of
+                input_circuit to input wires of self. The key and value
+                can either be of type Qubit or Clbit depending on the
+                type of the node.
 
         Raises:
             DAGCircuitError: if missing, duplicate or inconsistent wire
@@ -477,11 +478,12 @@ def compose_back(self, input_circuit, edge_map=None):
                 m_wire = edge_map.get(nd.wire, nd.wire)
                 # the mapped wire should already exist
                 if m_wire not in self.output_map:
-                    raise DAGCircuitError("wire %s[%d] not in self" % (m_wire[0].name, m_wire[1]))
+                    raise DAGCircuitError("wire %s[%d] not in self" % (
+                        m_wire.register.name, m_wire.index))
 
                 if nd.wire not in input_circuit.wires:
                     raise DAGCircuitError("inconsistent wire type for %s[%d] in input_circuit"
-                                          % (nd.wire[0].name, nd.wire[1]))
+                                          % (nd.register.name, nd.wire.index))
 
             elif nd.type == "out":
                 # ignore output nodes
@@ -540,12 +542,13 @@ def compose_front(self, input_circuit, edge_map=None):
                 m_name = edge_map.get(nd.wire, nd.wire)
                 # the mapped wire should already exist
                 if m_name not in self.input_map:
-                    raise DAGCircuitError("wire %s[%d] not in self" % (m_name[0].name, m_name[1]))
+                    raise DAGCircuitError("wire %s[%d] not in self" % (
+                        m_name.register.name, m_name.index))
 
                 if nd.wire not in input_circuit.wires:
                     raise DAGCircuitError(
                         "inconsistent wire for %s[%d] in input_circuit"
-                        % (nd.wire[0].name, nd.wire[1]))
+                        % (nd.wire.register.name, nd.wire.index))
 
             elif nd.type == "in":
                 # ignore input nodes
@@ -692,7 +695,7 @@ def _full_pred_succ_maps(self, pred_map, succ_map, input_circuit,
                     self.output_map[w])[0]
                 if len(list(self._multi_graph.predecessors(self.output_map[w]))) != 1:
                     raise DAGCircuitError("too many predecessors for %s[%d] "
-                                          "output node" % (w[0], w[1]))
+                                          "output node" % (w.register, w.index))
 
         return full_pred_map, full_succ_map
 


Test patch: