Repository: Qiskit/qiskit

Issue:
marginal_counts is broken for pulse results
<!-- ⚠️ 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**: 0.18.0
- **Python version**: 3.9
- **Operating system**: OSx

### What is the current behavior?
`marginal_counts` is broken for pulse jobs. I


### Steps to reproduce the problem
```python
from qiskit import pulse, QuantumCircuit, schedule, transpile, execute, IBMQ
from qiskit.result import marginal_counts


IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')
backend = provider.get_backend('ibmq_armonk')

qc = QuantumCircuit(1,1)
qc.measure(0, 0)

job = backend.run(schedule(transpile(qc, backend), backend))
marginal_counts(job.result(), indices=[0])
```
Gives output
```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-8e897d2c2a54> in <module>
     11 
     12 job = backend.run(schedule(transpile(qc, backend), backend))
---> 13 marginal_counts(job.result(), indices=[0])

~/opt/anaconda3/envs/python39/lib/python3.9/site-packages/qiskit/result/utils.py in marginal_counts(result, indices, inplace, format_marginal)
     55             experiment_result.data.counts = new_counts_hex
     56             experiment_result.header.memory_slots = len(indices)
---> 57             csize = experiment_result.header.creg_sizes
     58             experiment_result.header.creg_sizes = _adjust_creg_sizes(csize, indices)
     59         return result

AttributeError: 'QobjExperimentHeader' object has no attribute 'creg_sizes'
```


### What is the expected behavior?



### Suggested solutions
It seems like it is assuming `creg` will be present in the header. This is not true for pulse jobs which do not have classical registers and therefore this field won't be present. The fix should make marginal_counts work when the header is empty.



Discussion:
What happens if you do `marginal_counts(job.result.get_counts()), indices=[0])`? That's my normal workflow for using `marginal_counts()` because using it with results ends up deepcopying and making it too slow.

Of course, that's independent of this bug though we should fix the function for pulse results too.
Thanks, Matthew. This works but as you noted there still is a 🐛

On Mon, May 17, 2021, 6:23 PM Matthew Treinish ***@***.***>
wrote:

> What happens if you do marginal_counts(job.result.get_counts()),
> indices=[0])? That's my normal workflow for using marginal_counts()
> because using it with results ends up deepcopying and making it too slow.
>
> Of course, that's independent of this bug though we should fix the
> function for pulse results too.
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/Qiskit/qiskit-terra/issues/6430#issuecomment-842650611>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAL3LNVE62QMVGM6UBBL5WLTOGCORANCNFSM45BHEM7A>
> .
>

I am new to quantum computing and would love to work on this issue.

Thanks @a-freakish! Assigning to you 😄  
This issue already has an open pr in progress: https://github.com/Qiskit/qiskit-terra/pull/6486
The referenced pr https://github.com/Qiskit/qiskit-terra/pull/6486 appears to be closed (b/c no further work done) ?  Should someone pick up this PR and finish it?
yes please @chetmurthy ! Remember to respect the @rithikaadiga's authorship in branch off their code. Shall I assign you?
Luciano, I'm new to the org, and to QC.  But this seems sufficiently "just a software problem" that, yes, I think I should have a go at it.  You can mark me down for working on it.

Resolving patch:
diff --git a/qiskit/result/utils.py b/qiskit/result/utils.py
--- a/qiskit/result/utils.py
+++ b/qiskit/result/utils.py
@@ -75,8 +75,9 @@ def marginal_counts(
 
             if indices is not None:
                 experiment_result.header.memory_slots = len(indices)
-                csize = experiment_result.header.creg_sizes
-                experiment_result.header.creg_sizes = _adjust_creg_sizes(csize, indices)
+                csize = getattr(experiment_result.header, "creg_sizes", None)
+                if csize is not None:
+                    experiment_result.header.creg_sizes = _adjust_creg_sizes(csize, indices)
 
             if getattr(experiment_result.data, "memory", None) is not None and indices is not None:
                 if marginalize_memory is False:


Test patch:
diff --git a/test/python/result/test_result.py b/test/python/result/test_result.py
--- a/test/python/result/test_result.py
+++ b/test/python/result/test_result.py
@@ -731,3 +731,18 @@ def test_memory_int_out(self):
         self.assertEqual(
             'Result for experiment "99" could not be found.', context.exception.message
         )
+
+    def test_marginal_counts_no_cregs(self):
+        """Test that marginal_counts without cregs See qiskit-terra/6430."""
+        raw_counts_1 = {"0x0": 4, "0x1": 7, "0x2": 10, "0x6": 5, "0x9": 11, "0xD": 9, "0x12": 8}
+        data_1 = models.ExperimentResultData(counts=dict(**raw_counts_1))
+        exp_result_header_1 = QobjExperimentHeader(memory_slots=5)
+        exp_result_1 = models.ExperimentResult(
+            shots=54, success=True, data=data_1, header=exp_result_header_1
+        )
+
+        result = Result(results=[exp_result_1], **self.base_result_args)
+
+        _ = marginal_counts(result, indices=[0])
+        marginal_counts_result = marginal_counts(result, indices=[0])
+        self.assertEqual(marginal_counts_result.get_counts(), {"0": 27, "1": 27})