Repository: Qiskit/qiskit

Issue:
Should be able to make a initial_layout using only integers in a list
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
I have gone over this before, but it is again brought up due to #1945.  It should be possible to set an `initial_layout` using a list of just integers, no `(QuantumRegister, int)` tuples.  For example, when mapping a Bell circuit to qubits 3 and 4 on qx4 the follow are equivalent:

`layout = [None, None, None, (QuantumRegister(2, 'q'), 0), (QuantumRegister(2, 'q'), 1)]`

`layout = [3, 4]`

Not only is this latter one cleaner and shorter, It gets `QuantumRegister` names that cause problems (#1945), and is the exact same method that is used in the `NLayout` for the Cython `StochasticMapper`.  The conversion to the internal method is essentially already encoded in the `NLayout.to_layout()` routine. 



Discussion:

Resolving patch:
diff --git a/qiskit/mapper/layout.py b/qiskit/mapper/layout.py
--- a/qiskit/mapper/layout.py
+++ b/qiskit/mapper/layout.py
@@ -281,3 +281,37 @@ def generate_trivial_layout(*regs):
         for reg in regs:
             layout.add_register(reg)
         return layout
+
+    @staticmethod
+    def generate_from_intlist(int_list, *qregs):
+        """Converts a list of integers to a Layout
+        mapping virtual qubits (index of the list) to
+        physical qubits (the list values).
+
+        Args:
+            int_list (list): A list of integers.
+            *qregs (QuantumRegisters): The quantum registers to apply
+                the layout to.
+        Returns:
+            Layout: The corresponding Layout object.
+        Raises:
+            LayoutError: Invalid input layout.
+        """
+        # check for duplicate values in list
+        if len(int_list) != len(set(int_list)):
+            raise LayoutError('Duplicate values not permitted in integer layout.')
+        n_qubits = sum(reg.size for reg in qregs)
+        # Check if list is too short to cover all qubits
+        if len(int_list) < n_qubits:
+            err_msg = 'Integer list length must equal number of qubits in circuit.'
+            raise LayoutError(err_msg)
+        out = Layout()
+        main_idx = 0
+        for qreg in qregs:
+            for idx in range(qreg.size):
+                out[(qreg, idx)] = int_list[main_idx]
+                main_idx += 1
+        if main_idx != len(int_list):
+            for int_item in int_list[main_idx:]:
+                out[int_item] = None
+        return out
diff --git a/qiskit/tools/compiler.py b/qiskit/tools/compiler.py
--- a/qiskit/tools/compiler.py
+++ b/qiskit/tools/compiler.py
@@ -11,7 +11,6 @@
 
 from qiskit.compiler import assemble_circuits, RunConfig
 from qiskit import transpiler
-from qiskit.mapper import Layout
 
 logger = logging.getLogger(__name__)
 
@@ -64,9 +63,6 @@ def compile(circuits, backend,
     if memory:
         run_config.memory = memory
 
-    if initial_layout is not None and not isinstance(initial_layout, Layout):
-        initial_layout = Layout(initial_layout)
-
     new_circuits = transpiler.transpile(circuits, backend, basis_gates, coupling_map,
                                         initial_layout, seed_mapper, pass_manager)
 
diff --git a/qiskit/transpiler/transpiler.py b/qiskit/transpiler/transpiler.py
--- a/qiskit/transpiler/transpiler.py
+++ b/qiskit/transpiler/transpiler.py
@@ -15,7 +15,7 @@
 from qiskit.converters import circuit_to_dag
 from qiskit.converters import dag_to_circuit
 from qiskit.extensions.standard import SwapGate
-from qiskit.mapper import Layout
+from qiskit.mapper.layout import Layout
 from qiskit.transpiler.passes.unroller import Unroller
 
 from .passes.cx_cancellation import CXCancellation
@@ -70,6 +70,18 @@ def transpile(circuits, backend=None, basis_gates=None, coupling_map=None,
     if not basis_gates:
         raise TranspilerError('no basis_gates or backend to compile to')
 
+    # Convert integer list format to Layout
+    if isinstance(initial_layout, list) and \
+            all(isinstance(elem, int) for elem in initial_layout):
+        if isinstance(circuits, list):
+            circ = circuits[0]
+        else:
+            circ = circuits
+        initial_layout = Layout.generate_from_intlist(initial_layout, *circ.qregs)
+
+    if initial_layout is not None and not isinstance(initial_layout, Layout):
+        initial_layout = Layout(initial_layout)
+
     circuits = parallel_map(_transpilation, circuits,
                             task_kwargs={'basis_gates': basis_gates,
                                          'coupling_map': coupling_map,


Test patch:
diff --git a/test/python/compiler/test_compiler.py b/test/python/compiler/test_compiler.py
--- a/test/python/compiler/test_compiler.py
+++ b/test/python/compiler/test_compiler.py
@@ -135,6 +135,41 @@ def test_mapping_correction(self):
 
         self.assertIsInstance(circuits, QuantumCircuit)
 
+    def test_transpiler_layout_from_intlist(self):
+        """A list of ints gives layout to correctly map circuit.
+        virtual  physical
+         q1_0  -  4   ---[H]---
+         q2_0  -  5
+         q2_1  -  6   ---[H]---
+         q3_0  -  8
+         q3_1  -  9
+         q3_2  -  10  ---[H]---
+
+        """
+        qr1 = QuantumRegister(1, 'qr1')
+        qr2 = QuantumRegister(2, 'qr2')
+        qr3 = QuantumRegister(3, 'qr3')
+        qc = QuantumCircuit(qr1, qr2, qr3)
+        qc.h(qr1[0])
+        qc.h(qr2[1])
+        qc.h(qr3[2])
+        layout = [4, 5, 6, 8, 9, 10]
+
+        cmap = [[1, 0], [1, 2], [2, 3], [4, 3], [4, 10],
+                [5, 4], [5, 6], [5, 9], [6, 8], [7, 8],
+                [9, 8], [9, 10], [11, 3], [11, 10],
+                [11, 12], [12, 2], [13, 1], [13, 12]]
+
+        new_circ = transpile(qc, backend=None,
+                             coupling_map=cmap,
+                             basis_gates=['u2'],
+                             initial_layout=layout)
+        mapped_qubits = []
+        for gate in new_circ.data:
+            mapped_qubits.append(gate.qargs[0][1])
+
+        self.assertEqual(mapped_qubits, [4, 6, 10])
+
     def test_mapping_multi_qreg(self):
         """Test mapping works for multiple qregs.
         """
diff --git a/test/python/test_layout.py b/test/python/test_layout.py
--- a/test/python/test_layout.py
+++ b/test/python/test_layout.py
@@ -11,7 +11,7 @@
 import unittest
 
 from qiskit import QuantumRegister
-from qiskit.mapper import Layout
+from qiskit.mapper.layout import Layout
 from qiskit.mapper.exceptions import LayoutError
 from qiskit.test import QiskitTestCase
 
@@ -25,7 +25,7 @@ def setUp(self):
     def test_default_layout(self):
         """Static method generate_trivial_layout creates a Layout"""
         qr0 = QuantumRegister(3, 'q0')
-        qr1 = QuantumRegister(2, 'q1')
+        qr1 = QuantumRegister(2, 'qr1')
         layout = Layout.generate_trivial_layout(qr0, qr1)
 
         self.assertEqual(layout[(qr0, 0)], 0)
@@ -50,22 +50,22 @@ def test_layout_from_dict(self):
     def test_layout_from_list(self):
         """Constructor from a list"""
         layout = Layout([(QuantumRegister(2, 'q0'), 0),
-                         (QuantumRegister(2, 'q1'), 0),
+                         (QuantumRegister(2, 'qr1'), 0),
                          None,
-                         (QuantumRegister(2, 'q1'), 1),
+                         (QuantumRegister(2, 'qr1'), 1),
                          (QuantumRegister(2, 'q0'), 1)])
 
         self.assertEqual(layout[(QuantumRegister(2, 'q0'), 0)], 0)
-        self.assertEqual(layout[(QuantumRegister(2, 'q1'), 0)], 1)
+        self.assertEqual(layout[(QuantumRegister(2, 'qr1'), 0)], 1)
         with self.assertRaises(KeyError):
             _ = layout[None]
-        self.assertEqual(layout[(QuantumRegister(2, 'q1'), 1)], 3)
+        self.assertEqual(layout[(QuantumRegister(2, 'qr1'), 1)], 3)
         self.assertEqual(layout[(QuantumRegister(2, 'q0'), 1)], 4)
 
         self.assertEqual(layout[0], (QuantumRegister(2, 'q0'), 0))
-        self.assertEqual(layout[1], (QuantumRegister(2, 'q1'), 0))
+        self.assertEqual(layout[1], (QuantumRegister(2, 'qr1'), 0))
         self.assertEqual(layout[2], None)
-        self.assertEqual(layout[3], (QuantumRegister(2, 'q1'), 1))
+        self.assertEqual(layout[3], (QuantumRegister(2, 'qr1'), 1))
         self.assertEqual(layout[4], (QuantumRegister(2, 'q0'), 1))
 
     def test_layout_set(self):
@@ -145,11 +145,11 @@ def test_layout_add_register(self):
         """add_register() method"""
         layout = Layout()
         layout.add_register(QuantumRegister(2, 'q0'))
-        layout.add_register(QuantumRegister(1, 'q1'))
+        layout.add_register(QuantumRegister(1, 'qr1'))
 
         self.assertEqual(layout[(QuantumRegister(2, 'q0'), 0)], 0)
         self.assertEqual(layout[(QuantumRegister(2, 'q0'), 1)], 1)
-        self.assertEqual(layout[(QuantumRegister(1, 'q1'), 0)], 2)
+        self.assertEqual(layout[(QuantumRegister(1, 'qr1'), 0)], 2)
 
     def test_physical_keyerror(self):
         """When asking for an unexistant physical qubit, KeyError"""
@@ -293,6 +293,90 @@ def test_layout_repr_with_holes(self):
         self.assertDictEqual(layout._p2v, repr_layout._p2v)
         self.assertDictEqual(layout._v2p, repr_layout._v2p)
 
+    def test_layout_from_intlist(self):
+        """Create a layout from a list of integers.
+        virtual  physical
+         q1_0  ->  4
+         q2_0  ->  5
+         q2_1  ->  6
+         q3_0  ->  8
+         q3_1  ->  9
+         q3_2  ->  10
+        """
+        qr1 = QuantumRegister(1, 'qr1')
+        qr2 = QuantumRegister(2, 'qr2')
+        qr3 = QuantumRegister(3, 'qr3')
+        intlist_layout = [4, 5, 6, 8, 9, 10]
+        layout = Layout.generate_from_intlist(intlist_layout, qr1, qr2, qr3)
+
+        expected = Layout({4: (QuantumRegister(1, 'qr1'), 0),
+                           5: (QuantumRegister(2, 'qr2'), 0),
+                           6: (QuantumRegister(2, 'qr2'), 1),
+                           8: (QuantumRegister(3, 'qr3'), 0),
+                           9: (QuantumRegister(3, 'qr3'), 1),
+                           10: (QuantumRegister(3, 'qr3'), 2)
+                           })
+        self.assertDictEqual(layout._p2v, expected._p2v)
+        self.assertDictEqual(layout._v2p, expected._v2p)
+
+    def test_layout_from_intlist_short(self):
+        """If the intlist is longer that your quantum register, map them to None.
+        virtual  physical
+         q1_0  ->  4
+         q2_0  ->  5
+         q2_1  ->  6
+         None  ->  8
+         None  ->  9
+         None  ->  10
+        """
+        qr1 = QuantumRegister(1, 'qr1')
+        qr2 = QuantumRegister(2, 'qr2')
+
+        intlist_layout = [4, 5, 6, 8, 9, 10]
+        layout = Layout.generate_from_intlist(intlist_layout, qr1, qr2)
+
+        expected = Layout({4: (QuantumRegister(1, 'qr1'), 0),
+                           5: (QuantumRegister(2, 'qr2'), 0),
+                           6: (QuantumRegister(2, 'qr2'), 1),
+                           8: None,
+                           9: None,
+                           10: None
+                           })
+        self.assertDictEqual(layout._p2v, expected._p2v)
+        self.assertDictEqual(layout._v2p, expected._v2p)
+
+    def test_layout_from_intlist_long(self):
+        """If the intlist is shorter that your quantum register, fail.
+        virtual  physical
+         q1_0  ->  4
+         q2_0  ->  5
+         q2_1  ->  6
+         q3_0  ->  8
+         q3_1  ->  ?
+         q3_2  ->  ?
+        """
+        qr1 = QuantumRegister(1, 'qr1')
+        qr2 = QuantumRegister(2, 'qr2')
+        qr3 = QuantumRegister(3, 'qr3')
+        intlist_layout = [4, 5, 6, 8]
+
+        with self.assertRaises(LayoutError):
+            _ = Layout.generate_from_intlist(intlist_layout, qr1, qr2, qr3)
+
+    def test_layout_from_intlist_duplicated(self):
+        """If the intlist contains duplicated ints, fail.
+        virtual  physical
+         q1_0  ->  4
+         q2_0  ->  6 -- This is
+         q2_1  ->  6 -- not allowed
+        """
+        qr1 = QuantumRegister(1, 'qr1')
+        qr2 = QuantumRegister(2, 'qr2')
+        intlist_layout = [4, 6, 6]
+
+        with self.assertRaises(LayoutError):
+            _ = Layout.generate_from_intlist(intlist_layout, qr1, qr2)
+
 
 if __name__ == '__main__':
     unittest.main()