Repository: Qiskit/qiskit

Issue:
ConsolidateBlocks raises for CX between two registers
From https://travis-ci.com/Qiskit/qiskit-terra/jobs/216588160#L6863:

```
>>> qr1 = qk.QuantumRegister(1)
>>> qr2 = qk.QuantumRegister(2)
>>> qc = qk.QuantumCircuit(qr2, qr1, cr)
>>> qc.cx(qr1[0], qr2[1])
>>> qc.measure(qr1[0], cr[0])
>>> qk.transpile(qc, optimization_level=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/compiler/transpile.py", line 187, in transpile
    circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_configs)))
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/tools/parallel.py", line 100, in parallel_map
    return [task(values[0], *task_args, **task_kwargs)]
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/compiler/transpile.py", line 208, in _transpile_circuit
    return transpile_circuit(circuit, transpile_config)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/transpiler/transpile_circuit.py", line 65, in transpile_circuit
    return pass_manager.run(circuit)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 171, in run
    dag = self._do_pass(pass_, dag, passset.options)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 202, in _do_pass
    dag = self._run_this_pass(pass_, dag)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 215, in _run_this_pass
    new_dag = pass_.run(dag)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/transpiler/passes/consolidate_blocks.py", line 93, in run
    subcirc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/circuit/quantumcircuit.py", line 359, in append
    instructions.add(self._append(instruction, qarg, carg), qarg, carg)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/circuit/quantumcircuit.py", line 382, in _append
    self._check_dups(qargs)
  File "/Users/kevin.krsulichibm.com/q/qiskit-terra/qiskit/circuit/quantumcircuit.py", line 438, in _check_dups
    raise QiskitError("duplicate qubit arguments")
qiskit.exceptions.QiskitError: 'duplicate qubit arguments'
```


Discussion:
.. and this one if you don't mind @maddy-tod  :)

Resolving patch:
diff --git a/qiskit/transpiler/passes/consolidate_blocks.py b/qiskit/transpiler/passes/consolidate_blocks.py
--- a/qiskit/transpiler/passes/consolidate_blocks.py
+++ b/qiskit/transpiler/passes/consolidate_blocks.py
@@ -19,7 +19,7 @@
 The blocks are collected by a previous pass, such as Collect2qBlocks.
 """
 
-from qiskit.circuit import QuantumRegister, QuantumCircuit, Qubit
+from qiskit.circuit import QuantumRegister, QuantumCircuit
 from qiskit.dagcircuit import DAGCircuit
 from qiskit.quantum_info.operators import Operator
 from qiskit.quantum_info.synthesis import TwoQubitBasisDecomposer
@@ -57,12 +57,7 @@ def run(self, dag):
             new_dag.add_creg(creg)
 
         # compute ordered indices for the global circuit wires
-        global_index_map = {}
-        for wire in dag.wires:
-            if not isinstance(wire, Qubit):
-                continue
-            global_qregs = list(dag.qregs.values())
-            global_index_map[wire] = global_qregs.index(wire.register) + wire.index
+        global_index_map = {wire: idx for idx, wire in enumerate(dag.qubits())}
 
         blocks = self.property_set['block_list']
         # just to make checking if a node is in any block easier


Test patch:
diff --git a/test/python/transpiler/test_consolidate_blocks.py b/test/python/transpiler/test_consolidate_blocks.py
--- a/test/python/transpiler/test_consolidate_blocks.py
+++ b/test/python/transpiler/test_consolidate_blocks.py
@@ -149,6 +149,30 @@ def test_block_spanning_two_regs(self):
         fidelity = process_fidelity(new_dag.op_nodes()[0].op.to_matrix(), unitary.to_matrix())
         self.assertAlmostEqual(fidelity, 1.0, places=7)
 
+    def test_block_spanning_two_regs_different_index(self):
+        """blocks spanning wires on different quantum registers work when the wires
+        could have conflicting indices. This was raised in #2806 when a CX was applied
+        across multiple registers and their indices collided, raising an error."""
+        qr0 = QuantumRegister(1, "qr0")
+        qr1 = QuantumRegister(2, "qr1")
+        qc = QuantumCircuit(qr0, qr1)
+        qc.cx(qr0[0], qr1[1])
+        dag = circuit_to_dag(qc)
+
+        pass_ = ConsolidateBlocks(force_consolidate=True)
+        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
+        new_dag = pass_.run(dag)
+
+        sim = UnitarySimulatorPy()
+        original_result = execute(qc, sim).result()
+        original_unitary = UnitaryGate(original_result.get_unitary())
+
+        from qiskit.converters import dag_to_circuit
+        new_result = execute(dag_to_circuit(new_dag), sim).result()
+        new_unitary = UnitaryGate(new_result.get_unitary())
+
+        self.assertEqual(original_unitary, new_unitary)
+
     def test_node_added_before_block(self):
         """Test that a node before a block remains before the block