Skip to content

Commit 19d45c4

Browse files
Merge branch 'dev' into feat-Doctest
2 parents f267b01 + c1661ce commit 19d45c4

19 files changed

+178
-174
lines changed

docs/_static/custom.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ window.onload = () => {
4343
// move the constants of a module to appear first in the module
4444
document.querySelectorAll(".target").forEach((moduleMarker) => {
4545
if (moduleMarker.id.startsWith("module-")) {
46-
appendAfter = moduleMarker;
46+
module_description =
47+
moduleMarker.parentElement.querySelectorAll(".target ~ p");
48+
if (module_description.length != 0)
49+
appendAfter = module_description[module_description.length - 1];
50+
else appendAfter = moduleMarker;
4751
sibling = moduleMarker.nextSibling;
4852
for (; sibling; ) {
4953
next = sibling.nextSibling;

docs/circuit.rst

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ The Quantum Circuit
33

44
.. code-block:: python
55
6-
from mpqp import QCircuit
6+
from mpqp import QCircuit
77
88
.. automodule:: mpqp.core.circuit
9-
:members:
10-
:undoc-members:
11-
:show-inheritance:

docs/tools.rst

+14-41
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,16 @@ Tools
33

44
Some additional tools are provided with our library. Even though most of them
55
are geared at internal usage, they are all presented here. Amongst them, the
6-
ones most probable of being of use for you are in:
7-
8-
- the section :ref:`viz` presents visualization tools for several data types.
9-
They might be integrated in these types if they are popular enough.
10-
- the section :ref:`math` presents mathematical tools for linear algebra,
11-
functions generalized to more data types, etc...
12-
13-
.. _viz:
14-
15-
Visualization
16-
-------------
17-
18-
.. code-block::python
19-
20-
from mpqp.tools.visualization import *
21-
22-
.. automodule:: mpqp.tools.visualization
6+
ones most probable of being of use for you are in the :ref:`math` section,
7+
presenting mathematical tools for linear algebra, functions generalized to more
8+
data types, etc...
239

2410
.. _math:
2511

2612
Useful Maths Operations
2713
-----------------------
2814

29-
.. code-block::python
15+
.. code-block:: python
3016
3117
from mpqp.tools.maths import *
3218
@@ -35,42 +21,29 @@ Useful Maths Operations
3521
Generics
3622
--------
3723

38-
We centralize generic types and associated or general recurrent manipulations in
39-
a single module.
24+
.. code-block:: python
25+
26+
from mpqp.tools.generics import *
4027
4128
.. automodule:: mpqp.tools.generics
4229

4330
Errors
4431
------
4532

46-
In order to provide more explicit messages concerning errors that the user can
47-
encounter while using the library, we introduce custom exceptions. When it is
48-
relevant, we also append the trace of the error raised by a provider's SDK.
33+
.. code-block:: python
34+
35+
from mpqp.tools.errors import *
4936
5037
.. automodule:: mpqp.tools.errors
5138

5239
Choice Tree
5340
-----------
5441

55-
This module provides functionalities for working with decision trees, allowing for
56-
seamless navigation and interaction within a tree structure.
57-
58-
The user defines a :class:`QuestionNode<mpqp.tools.choice_tree.QuestionNode>`,
59-
containing a question or requesting and answer from the user. Then the user can
60-
select among a list of possible answers, encoded in
61-
:class:`AnswerNode<mpqp.tools.choice_tree.AnswerNode>`. For each answer, either
62-
another question will follow, or an action can be executed.
63-
64-
65-
.. autoclass:: mpqp.tools.choice_tree.AnswerNode
66-
67-
.. autoclass:: mpqp.tools.choice_tree.QuestionNode
42+
.. code-block:: python
6843
69-
To execute the choice tree in a console mode, one has to execute the function
70-
:func:`run_choice_tree<mpqp.tools.choice_tree.run_choice_tree>` while giving the
71-
root ``QuestionNode`` in the choice tree.
44+
from mpqp.tools.choice_tree import *
7245
73-
.. autofunction:: mpqp.tools.choice_tree.run_choice_tree
46+
.. automodule:: mpqp.tools.choice_tree
7447

7548
Example
7649
^^^^^^^
@@ -99,7 +72,7 @@ Example
9972
),
10073
AnswerNode(
10174
"Coffee",
102-
lambda: ("I get it, ou gotta do what you gota do to stay awake", []),
75+
lambda: ("I get it, you gotta do what you gotta do to stay awake", []),
10376
QuestionNode(
10477
"And how do you like it?",
10578
[

docs/vqa.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Once you define a circuit with variables, you have two options:
2828

2929
1. either the measure of the circuit is an
3030
:class:`ExpectationMeasure<mpqp.core.instruction.measurement.expectation_value.ExpectationMeasure>`
31-
can directly feed it in the optimizer;
31+
and can directly feed it in the optimizer;
3232
2. or you can define a custom cost function for more complicated cases.
3333

3434
Detailed example for those two options can be found in our example notebooks.

examples/scripts/bell_pair.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from mpqp.execution.devices import AWSDevice, IBMDevice
88
from mpqp.gates import CNOT, H
99
from mpqp.measures import BasisMeasure
10-
from mpqp.tools.visualization import plot_results_sample_mode
1110

1211
# Declaration of the circuit with the right size
1312
circuit = QCircuit(2, label="Bell pair")
@@ -18,6 +17,6 @@
1817
results = run(circuit, [IBMDevice.AER_SIMULATOR, AWSDevice.BRAKET_LOCAL_SIMULATOR])
1918
print(results)
2019

21-
plot_results_sample_mode(results)
20+
results.plot(show=False)
2221
circuit.display()
2322
plt.show()

examples/scripts/cirq_experiments.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
# %%
2-
import matplotlib.pyplot as plt
3-
42
from mpqp import QCircuit
53
from mpqp.core.languages import Language
64
from mpqp.execution import run
75
from mpqp.execution.connection.google_connection import config_ionq_account
86
from mpqp.execution.devices import GOOGLEDevice, IBMDevice
97
from mpqp.gates import H, Rx, Ry, Rz
108
from mpqp.measures import BasisMeasure
11-
from mpqp.tools.visualization import plot_results_sample_mode
129

1310
# %%
1411
circuit = QCircuit(3)
@@ -34,8 +31,7 @@
3431
)
3532
print(results)
3633

37-
plot_results_sample_mode(results)
38-
plt.show()
34+
results.plot()
3935

4036
# %%
4137
cirq_circuit = circuit.to_other_language(Language.CIRQ)
@@ -54,5 +50,4 @@
5450
results = run(circuit, [GOOGLEDevice.IONQ_SIMULATOR])
5551
print(results)
5652

57-
plot_results_sample_mode(results)
58-
plt.show()
53+
results.plot()

examples/scripts/demonstration.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
"""Demonstration MPQP"""
22

3-
import matplotlib.pyplot as plt
43
import numpy as np
54

65
from mpqp import QCircuit
76
from mpqp.execution import run
87
from mpqp.execution.devices import ATOSDevice, AWSDevice, GOOGLEDevice, IBMDevice
98
from mpqp.gates import *
109
from mpqp.measures import BasisMeasure
11-
from mpqp.tools.visualization import plot_results_sample_mode
1210

1311
# Constructing the circuit
1412
meas = BasisMeasure(list(range(3)), shots=2000)
@@ -31,8 +29,7 @@
3129
print(results)
3230

3331
# Display the circuit
34-
plot_results_sample_mode(results)
35-
plt.show()
32+
results.plot()
3633

3734
c = QCircuit([T(0), CNOT(0, 1), Ry(np.pi / 2, 2), S(1), CZ(2, 1), SWAP(2, 0)])
3835
res = run(

mpqp/core/circuit.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from copy import deepcopy
2424
from numbers import Complex
25+
from pickle import dumps
2526
from typing import TYPE_CHECKING, Iterable, Optional, Sequence, Type, Union
2627

2728
if TYPE_CHECKING:
@@ -126,6 +127,9 @@ def __init__(
126127
self.nb_qubits = nb_qubits
127128
self.add(map(deepcopy, data))
128129

130+
def __eq__(self, value: object) -> bool:
131+
return dumps(self) == dumps(value)
132+
129133
def add(self, instruction: Instruction | Iterable[Instruction]):
130134
"""Adds one instruction or a list of instructions at the end of the
131135
circuit.
@@ -438,7 +442,7 @@ def optimize(self, criteria: Optional[str | list[str]] = None) -> QCircuit:
438442
>>>
439443
>>>
440444
441-
# 6M-TODO implement, example and test, can be an internship
445+
# 6M-TODO implement, example and test
442446
"""
443447
# ideas: a circuit can be optimized
444448
# - to reduce the depth of the circuit (combine gates, simplify some sequences)

mpqp/core/instruction/gates/native_gates.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,10 @@ def __init__(self, target: int):
365365

366366

367367
class T(OneQubitNoParamGate):
368-
"""One qubit T gate. It consists in applying a phase of Pi/4.
369-
The T gate can be defined as the fourth-root of the Z (Pauli) gate.
368+
r"""One qubit T gate. It is also referred to as the `\pi/4` gate because it
369+
consists in applying the phase gate with a phase of `\pi/4`.
370+
371+
The T gate can also be defined as the fourth-root of the Z (Pauli) gate.
370372
371373
Args:
372374
target: Index referring to the qubit on which the gate will be applied.

mpqp/core/instruction/instruction.py

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from abc import ABC, abstractmethod
77
from copy import deepcopy
88
from numbers import Complex
9+
from pickle import dumps
910
from typing import TYPE_CHECKING, Any, Optional
1011

1112
from sympy import Expr
@@ -96,6 +97,9 @@ def to_other_language(
9697
"""
9798
pass
9899

100+
def __eq__(self, value: object) -> bool:
101+
return dumps(self) == dumps(value)
102+
99103
def __str__(self) -> str:
100104
from mpqp.core.circuit import QCircuit
101105

mpqp/execution/result.py

+72
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
from __future__ import annotations
2323

2424
import math
25+
import random
2526
from numbers import Complex
2627
from typing import Optional
2728

2829
import numpy as np
2930
import numpy.typing as npt
31+
from matplotlib import pyplot as plt
3032
from typeguard import typechecked
3133

3234
from mpqp.execution.devices import AvailableDevice
@@ -391,6 +393,50 @@ def __str__(self):
391393
f"Job type {self.job.job_type} not implemented for __str__ method"
392394
)
393395

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+
394440

395441
@typechecked
396442
class BatchResult:
@@ -461,3 +507,29 @@ def __repr__(self):
461507

462508
def __getitem__(self, index: int):
463509
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()

mpqp/execution/runner.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def generate_job(
113113
if isinstance(measurement, BasisMeasure):
114114
# 3M-TODO: handle other basis by adding the right rotation (change
115115
# of basis) before measuring in the computational basis
116-
# 3M-TODO: Muhammad circuit.add(CustomGate(UnitaryMatrix(change_of_basis_inverse)))
116+
# Muhammad: circuit.add(CustomGate(UnitaryMatrix(change_of_basis_inverse)))
117117
if measurement.shots <= 0:
118118
job = Job(JobType.STATE_VECTOR, circuit, device)
119119
else:

0 commit comments

Comments
 (0)