Skip to content

Commit c1e13ea

Browse files
Merge pull request #39 from ColibrITD-SAS/feat-result-formatting
inconsistent result formatting
2 parents bade918 + 7ca4d5f commit c1e13ea

File tree

6 files changed

+106
-45
lines changed

6 files changed

+106
-45
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ __pycache__/
1010
.pytest_cache/
1111
.dockerenv
1212
.env
13-
.idea/
13+
.idea/
14+
.vs/

mpqp/execution/providers/ibm.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def compute_expectation_value(
7777
"type ExpectationMeasure"
7878
)
7979
nb_shots = job.measure.shots
80-
qiskit_observable = job.measure.observable.to_other_language(Language.QISKIT)
80+
qiskit_observable: Operator = job.measure.observable.to_other_language(
81+
Language.QISKIT
82+
) # pyright: ignore[reportAssignmentType]
8183

8284
if nb_shots != 0:
8385
assert ibm_backend is not None
@@ -123,7 +125,8 @@ def check_job_compatibility(job: Job):
123125
):
124126
raise DeviceJobIncompatibleError(
125127
"Cannot reconstruct state vector with this device. Please use "
126-
f"{IBMDevice.AER_SIMULATOR_STATEVECTOR} instead"
128+
f"{IBMDevice.AER_SIMULATOR_STATEVECTOR} instead (or change the job "
129+
"type, by for example giving a number of shots to the measure)."
127130
)
128131
if job.device == IBMDevice.AER_SIMULATOR_STATEVECTOR:
129132
if job.job_type == JobType.SAMPLE:
@@ -250,7 +253,9 @@ def submit_ibmq(job: Job) -> tuple[str, RuntimeJob | IBMJob]:
250253
if job.job_type == JobType.OBSERVABLE:
251254
assert isinstance(job.measure, ExpectationMeasure)
252255
estimator = Runtime_Estimator(session=session)
253-
qiskit_observable: Operator = job.measure.observable.to_other_language(Language.QISKIT)
256+
qiskit_observable: Operator = job.measure.observable.to_other_language(
257+
Language.QISKIT
258+
) # pyright: ignore[reportAssignmentType]
254259

255260
ibm_job = estimator.run(
256261
qiskit_circuit, qiskit_observable, shots=job.measure.shots

mpqp/execution/result.py

+27-27
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import math
44
from numbers import Complex
5-
from textwrap import dedent
65
from typing import Optional
76

87
import numpy as np
@@ -61,10 +60,11 @@ def amplitudes(self):
6160
return self.vector
6261

6362
def __str__(self):
64-
return f"""
65-
State vector: {self.vector}
66-
Probabilities: {self.probabilities}
67-
Number of qubits: {self.nb_qubits}"""
63+
cleaned_vector = str(self.vector).replace("\n", " ")
64+
cleaned_probas = str(self.probabilities).replace("\n", " ")
65+
return f"""State vector: {cleaned_vector}
66+
Probabilities: {cleaned_probas}
67+
Number of qubits: {self.nb_qubits}"""
6868

6969

7070
@typechecked
@@ -261,7 +261,6 @@ def __init__(
261261
assert sample.count is not None
262262
counts[sample.index] = sample.count
263263
self._counts = counts
264-
# if is_counts shots != 0
265264
assert shots != 0
266265
self._probabilities = np.array(counts, dtype=float) / self.shots
267266
for sample in self._samples:
@@ -272,6 +271,7 @@ def __init__(
272271
" either `count` or `probability` (and the non-None "
273272
"attribute amongst the two must be the same in all samples)."
274273
)
274+
self.samples.sort(key=lambda sample: sample.bin_str)
275275
else:
276276
raise ValueError(f"{job.job_type} not handled")
277277

@@ -345,24 +345,24 @@ def counts(self) -> list[int]:
345345

346346
def __str__(self):
347347
header = f"Result: {type(self.device).__name__}, {self.device.name}"
348+
348349
if self.job.job_type == JobType.SAMPLE:
349-
samples_str = ("\n" + " " * 16).join(map(str, self.samples))
350+
samples_str = "\n".join(map(lambda s: f" {s}", self.samples))
350351
cleaned_probas = str(self._probabilities).replace("\n", " ")
351-
return header + dedent(
352-
f"""
353-
Counts: {self._counts}
354-
Probabilities: {cleaned_probas}
355-
{samples_str}
356-
Error: {self.error}\n\n"""
357-
)
352+
return f"""{header}
353+
Counts: {self._counts}
354+
Probabilities: {cleaned_probas}
355+
{samples_str}
356+
Error: {self.error}"""
357+
358358
if self.job.job_type == JobType.STATE_VECTOR:
359-
return f"""{header}\n{self._state_vector}\n\n"""
359+
return header + "\n" + str(self.state_vector)
360+
360361
if self.job.job_type == JobType.OBSERVABLE:
361-
return header + dedent(
362-
f"""
363-
Expectation value: {self.expectation_value}
364-
Error/Variance: {self.error}\n\n"""
365-
)
362+
return f"""{header}
363+
Expectation value: {self.expectation_value}
364+
Error/Variance: {self.error}"""
365+
366366
raise NotImplementedError(
367367
f"Job type {self.job.job_type} not implemented for __str__ method"
368368
)
@@ -403,22 +403,22 @@ class BatchResult:
403403
BatchResult: 3 results
404404
Result: ATOSDevice, MYQLM_PYLINALG
405405
State vector: [ 0.5+0.j 0.5+0.j 0.5+0.j -0.5+0.j]
406-
Probabilities: [0.25 0.25 0.25 0.25]
407-
Number of qubits: 2
406+
Probabilities: [0.25 0.25 0.25 0.25]
407+
Number of qubits: 2
408408
Result: ATOSDevice, MYQLM_PYLINALG
409409
Counts: [250, 0, 0, 250]
410410
Probabilities: [0.5 0. 0. 0.5]
411-
State: 00, Index: 0, Count: 250, Probability: 0.5
412-
State: 11, Index: 3, Count: 250, Probability: 0.5
411+
State: 00, Index: 0, Count: 250, Probability: 0.5
412+
State: 11, Index: 3, Count: 250, Probability: 0.5
413413
Error: 0.034
414414
Result: ATOSDevice, MYQLM_PYLINALG
415415
Expectation value: -3.09834
416416
Error/Variance: 0.021
417417
>>> print(batch_result[0])
418418
Result: ATOSDevice, MYQLM_PYLINALG
419-
State vector: [ 0.5+0.j 0.5+0.j 0.5+0.j -0.5+0.j]
420-
Probabilities: [0.25 0.25 0.25 0.25]
421-
Number of qubits: 2
419+
State vector: [ 0.5+0.j 0.5+0.j 0.5+0.j -0.5+0.j]
420+
Probabilities: [0.25 0.25 0.25 0.25]
421+
Number of qubits: 2
422422
"""
423423

424424
def __init__(self, results: list[Result]):

mpqp/execution/runner.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def _run_single(
127127
Result: IBMDevice, AER_SIMULATOR
128128
Counts: [512, 0, 0, 488]
129129
Probabilities: [0.512 0. 0. 0.488]
130-
State: 00, Index: 0, Count: 512, Probability: 0.512
131-
State: 11, Index: 3, Count: 488, Probability: 0.488
130+
State: 00, Index: 0, Count: 512, Probability: 0.512
131+
State: 11, Index: 3, Count: 488, Probability: 0.488
132132
Error: None
133133
"""
134134
job = generate_job(circuit, device, values)
@@ -172,8 +172,8 @@ def run(
172172
Result: IBMDevice, AER_SIMULATOR
173173
Counts: [512, 0, 0, 488]
174174
Probabilities: [0.512 0. 0. 0.488]
175-
State: 00, Index: 0, Count: 512, Probability: 0.512
176-
State: 11, Index: 3, Count: 488, Probability: 0.488
175+
State: 00, Index: 0, Count: 512, Probability: 0.512
176+
State: 11, Index: 3, Count: 488, Probability: 0.488
177177
Error: None
178178
>>> batch_result = run(
179179
... c,
@@ -184,14 +184,14 @@ def run(
184184
Result: AWSDevice, BRAKET_LOCAL_SIMULATOR
185185
Counts: [492, 0, 0, 508]
186186
Probabilities: [0.492 0. 0. 0.508]
187-
State: 00, Index: 0, Count: 492, Probability: 0.492
188-
State: 11, Index: 3, Count: 508, Probability: 0.508
187+
State: 00, Index: 0, Count: 492, Probability: 0.492
188+
State: 11, Index: 3, Count: 508, Probability: 0.508
189189
Error: None
190190
Result: ATOSDevice, MYQLM_PYLINALG
191191
Counts: [462, 0, 0, 538]
192192
Probabilities: [0.462 0. 0. 0.538]
193-
State: 00, Index: 0, Count: 462, Probability: 0.462
194-
State: 11, Index: 3, Count: 538, Probability: 0.538
193+
State: 00, Index: 0, Count: 462, Probability: 0.462
194+
State: 11, Index: 3, Count: 538, Probability: 0.538
195195
Error: 0.015773547629015002
196196
"""
197197

mpqp/tools/visualization.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def plot_results_sample_mode(results: Union[BatchResult, Result]):
2727

2828
return _prep_plot(results)
2929

30-
n_cols = math.ceil(len(results.results) // 2)
31-
n_rows = 2
30+
n_cols = math.ceil((len(results.results) + 1) // 2)
31+
n_rows = math.ceil(len(results.results) / n_cols)
3232

3333
for index, result in enumerate(results.results):
3434
plt.subplot(n_rows, n_cols, index + 1)

tests/execution/test_result.py

+59-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from __future__ import annotations
22

3-
from numpy import pi
3+
import numpy as np
44
import pytest
5+
from numpy import pi
56

67
from mpqp import QCircuit
8+
from mpqp.execution import Job, JobType, Result, Sample, StateVector
9+
from mpqp.execution.devices import IBMDevice
710
from mpqp.gates import *
811
from mpqp.measures import BasisMeasure
9-
from mpqp.execution import Result, StateVector, Sample, Job, JobType
10-
from mpqp.execution.devices import IBMDevice
1112

1213

1314
@pytest.mark.parametrize(
@@ -32,7 +33,7 @@ def test_result_wrong_type(job_type: JobType, data: float | StateVector | list[S
3233
@pytest.mark.parametrize(
3334
"job_type, data",
3435
[
35-
(JobType.STATE_VECTOR, StateVector([0.5, 0.5, 0.5, 0.5])),
36+
(JobType.STATE_VECTOR, StateVector(np.ones(4, dtype=np.complex64) / 2)),
3637
(JobType.OBSERVABLE, 0.4),
3738
(
3839
JobType.SAMPLE,
@@ -54,3 +55,57 @@ def test_result_right_type(job_type: JobType, data: float | StateVector | list[S
5455
shots = 0
5556
r = Result(j, data, shots=shots)
5657
assert r.device == r.job.device
58+
59+
60+
@pytest.mark.parametrize(
61+
"result, expected_string",
62+
[
63+
(
64+
Result(
65+
Job(
66+
JobType.STATE_VECTOR,
67+
QCircuit(2),
68+
IBMDevice.AER_SIMULATOR_STATEVECTOR,
69+
),
70+
StateVector(np.ones(4, dtype=np.complex64) / 2),
71+
),
72+
"""Result: IBMDevice, AER_SIMULATOR_STATEVECTOR
73+
State vector: [0.5+0.j 0.5+0.j 0.5+0.j 0.5+0.j]
74+
Probabilities: [0.25 0.25 0.25 0.25]
75+
Number of qubits: 2""",
76+
),
77+
(
78+
Result(
79+
Job(
80+
JobType.SAMPLE,
81+
QCircuit(2),
82+
IBMDevice.AER_SIMULATOR,
83+
measure=BasisMeasure([0, 1]),
84+
),
85+
[
86+
Sample(2, index=0, count=135),
87+
Sample(2, index=1, count=226),
88+
Sample(2, index=2, count=8),
89+
Sample(2, index=3, count=231),
90+
],
91+
shots=600,
92+
),
93+
"""Result: IBMDevice, AER_SIMULATOR
94+
Counts: [135, 226, 8, 231]
95+
Probabilities: [0.225 0.37666667 0.01333333 0.385 ]
96+
State: 00, Index: 0, Count: 135, Probability: 0.225
97+
State: 01, Index: 1, Count: 226, Probability: 0.37666666666666665
98+
State: 10, Index: 2, Count: 8, Probability: 0.013333333333333334
99+
State: 11, Index: 3, Count: 231, Probability: 0.385
100+
Error: None""",
101+
),
102+
(
103+
Result(Job(JobType.OBSERVABLE, QCircuit(2), IBMDevice.AER_SIMULATOR), 0.65),
104+
"""Result: IBMDevice, AER_SIMULATOR
105+
Expectation value: 0.65
106+
Error/Variance: None""",
107+
),
108+
],
109+
)
110+
def test_result_str(result: Result, expected_string: str):
111+
assert str(result) == expected_string

0 commit comments

Comments
 (0)