|
22 | 22 | from __future__ import annotations
|
23 | 23 |
|
24 | 24 | import math
|
| 25 | +import random |
25 | 26 | from numbers import Complex
|
26 | 27 | from typing import Optional
|
27 | 28 |
|
28 | 29 | import numpy as np
|
29 | 30 | import numpy.typing as npt
|
| 31 | +from matplotlib import pyplot as plt |
30 | 32 | from typeguard import typechecked
|
31 | 33 |
|
32 | 34 | from mpqp.execution.devices import AvailableDevice
|
@@ -391,6 +393,50 @@ def __str__(self):
|
391 | 393 | f"Job type {self.job.job_type} not implemented for __str__ method"
|
392 | 394 | )
|
393 | 395 |
|
| 396 | + def plot(self, show: bool = True): |
| 397 | + """Extract sampling info from the result and construct the bar diagram |
| 398 | + plot. |
| 399 | +
|
| 400 | + Args: |
| 401 | + show: ``plt.show()`` is only executed if ``show``, useful to batch |
| 402 | + plots. |
| 403 | + """ |
| 404 | + if show: |
| 405 | + plt.figure() |
| 406 | + |
| 407 | + x_array, y_array = self._to_display_lists() |
| 408 | + x_axis = range(len(x_array)) |
| 409 | + |
| 410 | + plt.bar(x_axis, y_array, color=(*[random.random() for _ in range(3)], 0.9)) |
| 411 | + plt.xticks(x_axis, x_array, rotation=-60) |
| 412 | + plt.xlabel("State") |
| 413 | + plt.ylabel("Counts") |
| 414 | + device = self.job.device |
| 415 | + plt.title(type(device).__name__ + "\n" + device.name) |
| 416 | + |
| 417 | + if show: |
| 418 | + plt.show() |
| 419 | + |
| 420 | + def _to_display_lists(self) -> tuple[list[str], list[int]]: |
| 421 | + """Transform a result into an x and y array containing the string of |
| 422 | + basis state with the associated counts. |
| 423 | +
|
| 424 | + Returns: |
| 425 | + The list of each basis state and the corresponding counts. |
| 426 | + """ |
| 427 | + if self.job.job_type != JobType.SAMPLE: |
| 428 | + raise NotImplementedError( |
| 429 | + f"{self.job.job_type} not handled, only {JobType.SAMPLE} is handled for now." |
| 430 | + ) |
| 431 | + if self.job.measure is None: |
| 432 | + raise ValueError( |
| 433 | + f"{self.job=} has no measure, making the counting impossible" |
| 434 | + ) |
| 435 | + n = self.job.measure.nb_qubits |
| 436 | + x_array = [f"|{bin(i)[2:].zfill(n)}⟩" for i in range(2**n)] |
| 437 | + y_array = self.counts |
| 438 | + return x_array, y_array |
| 439 | + |
394 | 440 |
|
395 | 441 | @typechecked
|
396 | 442 | class BatchResult:
|
@@ -461,3 +507,29 @@ def __repr__(self):
|
461 | 507 |
|
462 | 508 | def __getitem__(self, index: int):
|
463 | 509 | return self.results[index]
|
| 510 | + |
| 511 | + def plot(self, show: bool = True): |
| 512 | + """Display the result(s) using ``matplotlib.pyplot``. |
| 513 | +
|
| 514 | + The result(s) must be from a job who's ``job_type`` is ``SAMPLE``. They will |
| 515 | + be displayed as histograms. |
| 516 | +
|
| 517 | + If a ``BatchResult`` is given, the contained results will be displayed in a |
| 518 | + grid using subplots. |
| 519 | +
|
| 520 | + Args: |
| 521 | + show: ``plt.show()`` is only executed if ``show``, useful to batch |
| 522 | + plots. |
| 523 | + """ |
| 524 | + n_cols = math.ceil((len(self.results) + 1) // 2) |
| 525 | + n_rows = math.ceil(len(self.results) / n_cols) |
| 526 | + |
| 527 | + for index, result in enumerate(self.results): |
| 528 | + plt.subplot(n_rows, n_cols, index + 1) |
| 529 | + |
| 530 | + result.plot(show=False) |
| 531 | + |
| 532 | + plt.tight_layout() |
| 533 | + |
| 534 | + if show: |
| 535 | + plt.show() |
0 commit comments