Repository: Qiskit/qiskit (Python)

Issue:
Sampling issue of Qasm simulator at BasicAer
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: the master branch
- **Python version**: 3.7
- **Operating system**: macOS 10.14

### What is the current behavior?
Produce the correct measurement result


### Steps to reproduce the problem
```python
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit import BasicAer, Aer, execute
basicaer = BasicAer.get_backend('qasm_simulator')
aer = Aer.get_backend('qasm_simulator')
qr = QuantumRegister(2)
cr = ClassicalRegister(1)
qc = QuantumCircuit(qr, cr)
qc.h(qr[0])
qc.x(qr[1])
qc.measure(qr[1], cr[0])

basicaer_result = execute(qc, backend=basicaer).result().get_counts()
aer_result = execute(qc, backend=aer).result().get_counts()

print(basicaer_result)
print(aer_result)
```


### What is the expected behavior?
the results should be `{'1': 1024}` but BasicAer returns wrong results.


### Suggested solutions
No idea but it is related to the PR #2735 since before this PR, basic aer works correctly.
Furthermore, if all quantum registers are measured, the basic aer works okay. It seems that this issue only happened when only a part of quantum registers are measured.




Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 439a4307e2ae..319aa55ac1b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -108,6 +108,8 @@ The format is based on [Keep a Changelog].
 -   Fixed bug in CommutationAnalysis pass affecting conditional gates (\#2669)
 -   Fixed bug in measure sampling for BasicAer Qasm simulator if a qubit
     was measured into more than one memory cbit (\#2735)
+-   Fixed bug in measure sampling for BasicAer Qasm simulator if only a
+    subset of qubits are measured (\#2790)
 
 
 ## [0.8.2] - 2019-06-14
diff --git a/qiskit/providers/basicaer/qasm_simulator.py b/qiskit/providers/basicaer/qasm_simulator.py
index d3e9257bc0b9..500f7ed4ef1d 100644
--- a/qiskit/providers/basicaer/qasm_simulator.py
+++ b/qiskit/providers/basicaer/qasm_simulator.py
@@ -183,10 +183,13 @@ def _add_sample_measure(self, measure_params, num_samples):
         Returns:
             list: A list of memory values in hex format.
         """
-        # Get unique qubits that are actually measured
-        measured_qubits = list({qubit for qubit, cmembit in measure_params})
+        # Get unique qubits that are actually measured and sort in
+        # ascending order
+        measured_qubits = sorted(list({qubit for qubit, cmembit in measure_params}))
         num_measured = len(measured_qubits)
-        # Axis for numpy.sum to compute probabilities
+        # We use the axis kwarg for numpy.sum to compute probabilities
+        # this sums over all non-measured qubits to return a vector
+        # of measure probabilities for the measured qubits
         axis = list(range(self._number_of_qubits))
         for qubit in reversed(measured_qubits):
             # Remove from largest qubit to smallest so list position is correct
@@ -195,15 +198,18 @@ def _add_sample_measure(self, measure_params, num_samples):
         probabilities = np.reshape(np.sum(np.abs(self._statevector) ** 2,
                                           axis=tuple(axis)),
                                    2 ** num_measured)
-        # Generate samples on measured qubits
+        # Generate samples on measured qubits as ints with qubit
+        # position in the bit-string for each int given by the qubit
+        # position in the sorted measured_qubits list
         samples = self._local_random.choice(range(2 ** num_measured),
                                             num_samples, p=probabilities)
-        # Convert to bit-strings
+        # Convert the ints to bitstrings
         memory = []
         for sample in samples:
             classical_memory = self._classical_memory
             for qubit, cmembit in measure_params:
-                qubit_outcome = int((sample & (1 << qubit)) >> qubit)
+                pos = measured_qubits.index(qubit)
+                qubit_outcome = int((sample & (1 << pos)) >> pos)
                 membit = 1 << cmembit
                 classical_memory = (classical_memory & (~membit)) | (qubit_outcome << cmembit)
             value = bin(classical_memory)[2:]


Test patch:
diff --git a/test/python/basicaer/test_qasm_simulator.py b/test/python/basicaer/test_qasm_simulator.py
index 077fdb9b18fc..47677c3d7694 100644
--- a/test/python/basicaer/test_qasm_simulator.py
+++ b/test/python/basicaer/test_qasm_simulator.py
@@ -48,7 +48,7 @@ def test_qasm_simulator_single_shot(self):
         result = self.backend.run(self.qobj).result()
         self.assertEqual(result.success, True)
 
-    def test_qasm_simulator_measure_sampler(self):
+    def test_measure_sampler_repeated_qubits(self):
         """Test measure sampler if qubits measured more than once."""
         shots = 100
         qr = QuantumRegister(2, 'qr')
@@ -69,6 +69,55 @@ def test_qasm_simulator_measure_sampler(self):
         counts = result.get_counts(0)
         self.assertEqual(counts, target)
 
+    def test_measure_sampler_single_qubit(self):
+        """Test measure sampler if single-qubit is measured."""
+        shots = 100
+        num_qubits = 5
+        qr = QuantumRegister(num_qubits, 'qr')
+        cr = ClassicalRegister(1, 'cr')
+
+        for qubit in range(num_qubits):
+            circuit = QuantumCircuit(qr, cr)
+            circuit.x(qr[qubit])
+            circuit.measure(qr[qubit], cr[0])
+            target = {'1': shots}
+            job = execute(
+                circuit,
+                backend=self.backend,
+                shots=shots,
+                seed_simulator=self.seed)
+            result = job.result()
+            counts = result.get_counts(0)
+            self.assertEqual(counts, target)
+
+    def test_measure_sampler_partial_qubit(self):
+        """Test measure sampler if single-qubit is measured."""
+        shots = 100
+        num_qubits = 5
+        qr = QuantumRegister(num_qubits, 'qr')
+        cr = ClassicalRegister(4, 'cr')
+
+        circuit = QuantumCircuit(qr, cr)
+        circuit.x(qr[3])
+        circuit.x(qr[1])
+        circuit.barrier(qr)
+        circuit.measure(qr[3], cr[1])
+        circuit.barrier(qr)
+        circuit.measure(qr[1], cr[0])
+        circuit.barrier(qr)
+        circuit.measure(qr[0], cr[2])
+        circuit.barrier(qr)
+        circuit.measure(qr[3], cr[3])
+        target = {'1011': shots}
+        job = execute(
+            circuit,
+            backend=self.backend,
+            shots=shots,
+            seed_simulator=self.seed)
+        result = job.result()
+        counts = result.get_counts(0)
+        self.assertEqual(counts, target)
+
     def test_qasm_simulator(self):
         """Test data counts output for single circuit run against reference."""
         result = self.backend.run(self.qobj).result()
@@ -126,7 +175,7 @@ def test_teleport(self):
         circuit = QuantumCircuit(qr, cr0, cr1, cr2, name='teleport')
         circuit.h(qr[1])
         circuit.cx(qr[1], qr[2])
-        circuit.ry(pi/4, qr[0])
+        circuit.ry(pi / 4, qr[0])
         circuit.cx(qr[0], qr[1])
         circuit.h(qr[0])
         circuit.barrier(qr)
@@ -153,8 +202,8 @@ def test_teleport(self):
         self.log.info('test_teleport: data %s', data)
         self.log.info('test_teleport: alice %s', alice)
         self.log.info('test_teleport: bob %s', bob)
-        alice_ratio = 1/np.tan(pi/8)**2
-        bob_ratio = bob['0']/float(bob['1'])
+        alice_ratio = 1 / np.tan(pi / 8) ** 2
+        bob_ratio = bob['0'] / float(bob['1'])
         error = abs(alice_ratio - bob_ratio) / alice_ratio
         self.log.info('test_teleport: relative error = %s', error)
         self.assertLess(error, 0.05)