Measurements

from mpqp.measures import *

A measurement can be used to retrieve information about your quantum state. In mpqp, you can add it to a circuit as any other instruction (either when initializing the circuit, or using the add circuit method). All kind of measurements are listed bellow, check them out for usage example.

However, if no measurement is added to the circuit before running it, the user will retrieve the state as a StateVector in the computational basis (see section Results).

Note

In the current version, we only allow one measurement per circuit.

The measurement

Measure is the base class for measurements. It regroups all the attributes and methods common to all types of measurements we support.

A measurement can be of two types: BasisMeasure or ExpectationMeasure, described in details bellow.

class Measure(targets, shots=0, label=None)[source]

Bases: Instruction, ABC

Abstract class representing the measurement of the quantum state generated by a quantum circuit.

This class is used to regroup attributes and methods shared by all different types of measures.

We distinguish two types of measures:

  • Basis measurement (measure some qubits in a specific basis, sample mode, or retrieve the StateVector when shots is equal to zero)

  • Expectation value (use of an observable, exact or sample mode)

Parameters
  • targets (list[int]) – List of indices referring to the qubits on which the measure will be applied.

  • shots (int) – Number of times the circuit should be run, each of these times is called a shot.

  • label (Optional[str]) – Label used to identify the measure.

label

See parameter description.

shots

See parameter description.

Measuring in a basis

Choice of the basis

When we measure a quantum state, we project it in an orthonormal basis of the associated Hilbert space. By default, BasisMeasure operates in the computational basis, but you may want to measure the state in a custom basis, like it can be the case in the Bell game. For this purpose, you can use the Basis class.

On the other hand, some common basis are available for you to use: ComputationalBasis and HadamardBasis.

class Basis(basis_vectors, nb_qubits=None)[source]

Bases: object

Represents a basis of the Hilbert space used for measuring a qubit.

Parameters
  • basis_vectors (list[npt.NDArray[np.complex64]]) – List of vector composing the basis.

  • nb_qubits (Optional[int]) – Number of qubits associated with this basis. If not specified, it will be automatically inferred from basis_vectors’s dimensions.

Example

>>> Basis([np.array([1,0]), np.array([0,-1])]).pretty_print()
Basis: [
    [1, 0],
    [0, -1]
]
pretty_print()[source]

Nicer print for the basis, with human readable formatting.

Example

>>> Basis([np.array([1,0]), np.array([0,-1])]).pretty_print()
Basis: [
    [1, 0],
    [0, -1]
]
basis_vectors

See parameter description.

nb_qubits

See parameter description.

class ComputationalBasis(nb_qubits=None)[source]

Bases: VariableSizeBasis

Basis representing the computational basis, also called Z-basis or canonical basis.

Parameters

nb_qubits (Optional[int]) – number of qubits of the space, if not given as input (for example if unknown at the moment of creation) set_size will have to be executed before the basis is used (in a measure for example).

Examples

>>> ComputationalBasis(3).pretty_print()
Basis: [
    [1, 0, 0, 0, 0, 0, 0, 0],
    [0, 1, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0, 0],
    [0, 0, 0, 0, 0, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 0, 0, 0, 0, 1]
]
>>> b = ComputationalBasis()
>>> b.set_size(2)
>>> b.pretty_print()
Basis: [
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, 1]
]
set_size(nb_qubits)[source]

To allow the user to use a basis without having to specify the size (because implicitly the size should be the number of qubits of the circuit), we use this method, that will only be called once the circuit’s size is definitive (i.e. at the last moment before the circuit is ran)

Parameters

nb_qubits (int) – number of qubits in the basis

class HadamardBasis(nb_qubits=None)[source]

Bases: VariableSizeBasis

Basis representing the Hadamard basis, also called X-basis or +/- basis.

Parameters

nb_qubits (Optional[int]) – number of qubits in the basis

Example

>>> HadamardBasis(2).pretty_print()
Basis: [
    [0.5, 0.5, 0.5, 0.5],
    [0.5, -0.5, 0.5, -0.5],
    [0.5, 0.5, -0.5, -0.5],
    [0.5, -0.5, -0.5, 0.5]
]
set_size(nb_qubits)[source]

To allow the user to use a basis without having to specify the size (because implicitly the size should be the number of qubits of the circuit), we use this method, that will only be called once the circuit’s size is definitive (i.e. at the last moment before the circuit is ran)

Parameters

nb_qubits (int) – number of qubits in the basis

The BasisMeasure

The BasisMeasure is used to project the state on a statevector of a given Basis and returns the corresponding eigenvalue.

class BasisMeasure(targets, c_targets=None, shots=0, basis=None, label=None)[source]

Bases: Measure

Class representing a measure of one or several qubits in a specific basis.

By default, the computational basis will be used. The user can also precise a specific basis using the class Basis.

The number of shots indicates the number of time the measure is repeated. When shots is equal to 0 (by default), the simulator is used to produce exact value of the amplitudes/probabilities.

Parameters
  • targets (list[int]) – List of indices referring to the qubits on which the measure will be applied.

  • c_targets (Optional[list[int]]) – List of indices referring to the classical bits on which the measure will be applied.

  • shots (int) – Number of shots to be performed basis: basis in which the qubits should be measured.

  • basis (Optional[Basis]) – Basis in which the measure is performed. Defaults to ComputationalBasis()

  • label (Optional[str]) – Label used to identify the measure.

Examples

>>> c1 = QCircuit([H(0), H(1), CNOT(0,1)])
>>> c1.add(BasisMeasure([0, 1], shots=1024))
>>> c2 = QCircuit([H(0), H(1), CNOT(0,1)])
>>> c2.add(BasisMeasure([0, 1], shots=1024, basis=HadamardBasis()))
to_other_language(language=Language.QISKIT, qiskit_parameters=None)[source]

Transforms this instruction into the corresponding object in the language specified in the language arg.

By default, the instruction is translated to the corresponding one in Qiskit, since it is the interface we use to generate the OpenQASM code.

In the future, we will generate the OpenQASM code on our own, and this method will be used only for complex objects that are not tractable by OpenQASM (like hybrid structures).

Parameters
  • language (Language) – Enum representing the target language.

  • qiskit_parameters (Optional[set['Parameter']]) – We need to keep track of the parameters passed to qiskit in order not to define twice the same parameter. Defaults to set().

Returns

The corresponding instruction (gate or measure) in the target language.

basis

See parameter description.

c_targets

See parameter description.

Measuring using an observable

Information about the state can be retrieved using the expectation value of this state measured by an observable. This is done using the Observable class to define your observable, and a ExpectationMeasure to perform the measure.

class ExpectationMeasure(targets, observable, shots=0, label=None)[source]

Bases: Measure

This measure evaluates the expectation value of the output of the circuit measured by the observable given as input.

If the targets are not sorted and contiguous, some additional swaps will be needed. This will affect the performance of your circuit if run on noisy hardware. The swaps added can be checked out in the pre_measure attribute of the ExpectationMeasure.

Parameters
  • targets (list[int]) – List of indices referring to the qubits on which the measure will be applied.

  • observable (Observable) – Observable used for the measure.

  • shots (int) – Number of shots to be performed.

  • label (Optional[str]) – Label used to identify the measure.

Example

>>> obs = Observable(np.diag([0.7, -1, 1, 1]))
>>> c = QCircuit([H(0), CNOT(0,1), ExpectationMeasure([0,1], observable=obs, shots=10000)])
>>> run(c, ATOSDevice.MYQLM_PYLINALG).expectation_value 
0.85918
Warns

UserWarning – If the targets are not sorted and contiguous, some additional swaps will be needed. This will change the performance of your circuit is run on noisy hardware.

Parameters
  • targets (list[int]) –

  • observable (Observable) –

  • shots (int) –

  • label (Optional[str]) –

to_other_language(language=Language.QISKIT, qiskit_parameters=None)[source]

Transforms this instruction into the corresponding object in the language specified in the language arg.

By default, the instruction is translated to the corresponding one in Qiskit, since it is the interface we use to generate the OpenQASM code.

In the future, we will generate the OpenQASM code on our own, and this method will be used only for complex objects that are not tractable by OpenQASM (like hybrid structures).

Parameters
  • language (Language) – Enum representing the target language.

  • qiskit_parameters (Optional[set['Parameter']]) – We need to keep track of the parameters passed to qiskit in order not to define twice the same parameter. Defaults to set().

Returns

The corresponding instruction (gate or measure) in the target language.

Return type

None

observable

See parameter description.

pre_measure

Circuit added before the expectation measurement to correctly swap target qubits when their are note ordered or contiguous.

rearranged_targets

Adjusted list of target qubits when they are not initially sorted and contiguous.

class Observable(observable)[source]

Bases: object

Class defining an observable, used for evaluating expectation values.

An observable can be defined by using a Hermitian matrix, or using a combination of operators in a specific basis Pauli.

Parameters

observable (Matrix | PauliString) – can be either a Hermitian matrix representing the observable or PauliString representing the observable.

Raises
  • ValueError – If the input matrix is not Hermitian or does not have a square shape.

  • NumberQubitsError – If the number of qubits in the input observable does not match the number of target qubits.

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> matrix = np.array([[1, 0], [0, -1]])
>>> ps = 3 * I @ Z + 4 * X @ Y
>>> obs = Observable(matrix)
>>> obs2 = Observable(ps)
to_other_language(language, circuit=None)[source]

Converts the observable to the representation of another quantum programming language.

Parameters
  • language (Language) – The target programming language.

  • circuit (Optional[Cirq_Circuit]) – The Cirq circuit associated with the observable (required for cirq).

Returns

Depends on the target language.

Return type

Operator | QLMObservable | Hermitian | CirqPauliSum | CirqPauliString

Example

>>> obs = Observable(np.diag([0.7, -1, 1, 1]))
>>> obs_qiskit = obs.to_other_language(Language.QISKIT)
>>> print(obs_qiskit)
Operator([[ 0.69999999+0.j,  0.        +0.j,  0.        +0.j,
            0.        +0.j],
          [ 0.        +0.j, -1.        +0.j,  0.        +0.j,
            0.        +0.j],
          [ 0.        +0.j,  0.        +0.j,  1.        +0.j,
            0.        +0.j],
          [ 0.        +0.j,  0.        +0.j,  0.        +0.j,
            1.        +0.j]],
         input_dims=(2, 2), output_dims=(2, 2))
property matrix: Matrix

The matrix representation of the observable.

nb_qubits

Number of qubits of this observable.

property pauli_string: PauliString

The PauliString representation of the observable.

Pauli String

Represents Pauli strings, which is linear combinations of PauliMonomial which is a combination of PauliAtom. PauliString objects can be added, subtracted, and multiplied by scalars. They also support matrix multiplication with other PauliString objects.

class PauliString(monomials=None)[source]

Bases: object

Represents a Pauli string, a linear combination of Pauli monomials.

Parameters

monomials (Optional[list['PauliStringMonomial']]) – List of Pauli monomials.

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> I @ Z + 2 * Y @ I + X @ Z
1*I@Z + 2*Y@I + 1*X@Z

Note

Pauli atoms are named I, X, Y, and Z. If you have conflicts with the gates of the same name, you could:

  • Rename the Pauli atoms:

from mpqp.measures import X as Pauli_X,  Y as Pauli_Y
ps = Pauli_X + Pauli_Y/2
  • Import the Pauli atoms directly from the module:

from mpqp.measures import pauli_string
ps = pauli_string.X + pauli_string.Y/2
classmethod from_matrix(matrix)[source]

Constructs a PauliString from a matrix.

Parameters

matrix (Matrix) – Matrix from which the PauliString is generated

Returns

Pauli string decomposition of the matrix in parameter.

Return type

PauliString

Raises

ValueError – If the input matrix is not square or its dimensions are not a power of 2.

Example

>>> ps = PauliString.from_matrix(np.array([[0, 1], [1, 2]]))
>>> print(ps)
1*I + 1*X + -1*Z
round(round_off_till=4)[source]

Rounds the coefficients of the PauliString to a specified number of decimal places.

Parameters

round_off_till (int) – Number of decimal places to round the coefficients to. Defaults to 4.

Returns

A PauliString with coefficients rounded to the specified number

of decimal places.

Return type

PauliString

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = 0.6875*I@I + 0.1275*I@Z
>>> rounded_ps = ps.round(1)
>>> print(rounded_ps)
0.7*I@I + 0.1*I@Z
simplify(inplace=False)[source]

Simplifies the PauliString by combining identical terms and removing terms with null coefficients.

Parameters

inplace (bool) – Indicates if simplify should update self.

Returns

A simplified version of the PauliString.

Return type

PauliString

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = I@I - 2 *I@I + Z@I - Z@I
>>> simplified_ps = ps.simplify()
>>> print(simplified_ps)
-1*I@I
sort_monomials()[source]

Sorts the monomials of the PauliString based on their coefficients.

Returns

A new PauliString object with monomials sorted based on their coefficients,

in descending order.

Return type

PauliString

to_dict()[source]

Converts the PauliString object to a dictionary representation.

Returns

Dictionary representation of the PauliString object.

Return type

dict[str, float]

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = 1 * I@Z + 2 * I@I
>>> print(ps.to_dict())
{'II': 2, 'IZ': 1}
to_matrix()[source]

Converts the PauliString to a matrix representation.

Returns

Matrix representation of the PauliString.

Return type

Matrix

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = I + Z
>>> matrix_representation = ps.to_matrix()
>>> print(matrix_representation)
[[2.+0.j 0.+0.j]
 [0.+0.j 0.+0.j]]
property monomials: list[mpqp.core.instruction.measurement.pauli_string.PauliStringMonomial]

Gets the monomials of the PauliString.

Returns

The list of monomials in the PauliString.

property nb_qubits: int

Gets the number of qubits associated with the PauliString.

Returns

The number of qubits associated with the PauliString.

class PauliStringAtom(label, matrix)[source]

Bases: PauliStringMonomial

Represents a single Pauli operator acting on a qubit in a Pauli string.

Parameters
  • label (str) – The label representing the Pauli operator.

  • matrix (npt.NDArray[np.complex64]) – The matrix representation of the Pauli operator.

Raises

RuntimeError – New atoms cannot be created, you should use the available ones.

Note

All the atoms are already initialized. Available atoms are (I, X, Y, Z).

to_matrix()[source]

Converts the PauliString to a matrix representation.

Returns

Matrix representation of the PauliString.

Return type

ndarray[Any, dtype[complex64]]

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = I + Z
>>> matrix_representation = ps.to_matrix()
>>> print(matrix_representation)
[[2.+0.j 0.+0.j]
 [0.+0.j 0.+0.j]]
property atoms
property coef
property monomials

Gets the monomials of the PauliString.

Returns

The list of monomials in the PauliString.

property nb_qubits: int

Gets the number of qubits associated with the PauliString.

Returns

The number of qubits associated with the PauliString.

class PauliStringMonomial(coef=1, atoms=None)[source]

Bases: PauliString

Represents a monomial in a Pauli string, consisting of a coefficient and a list of PauliStringAtom objects.

Parameters
  • coef (Real | float) – The coefficient of the monomial.

  • atoms (Optional[list['PauliStringAtom']]) – The list of PauliStringAtom objects forming the monomial.

simplify(inplace=False)[source]

Simplifies the PauliString by combining identical terms and removing terms with null coefficients.

Parameters

inplace (bool) – Indicates if simplify should update self.

Returns

A simplified version of the PauliString.

Return type

PauliString

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = I@I - 2 *I@I + Z@I - Z@I
>>> simplified_ps = ps.simplify()
>>> print(simplified_ps)
-1*I@I
to_matrix()[source]

Converts the PauliString to a matrix representation.

Returns

Matrix representation of the PauliString.

Return type

Matrix

Example

>>> from mpqp.core.instruction.measurement.pauli_string import I, X, Y, Z
>>> ps = I + Z
>>> matrix_representation = ps.to_matrix()
>>> print(matrix_representation)
[[2.+0.j 0.+0.j]
 [0.+0.j 0.+0.j]]
property monomials: list['PauliStringMonomial']

Gets the monomials of the PauliString.

Returns

The list of monomials in the PauliString.

property nb_qubits: int

Gets the number of qubits associated with the PauliString.

Returns

The number of qubits associated with the PauliString.

I = I

Pauli-I atom representing the identity operator in a Pauli monomial or string. Matrix representation: \(\begin{pmatrix}1&0\\0&1\end{pmatrix}\)

X = X

Pauli-X atom representing the X operator in a Pauli monomial or string. Matrix representation: \(\begin{pmatrix}0&1\\1&0\end{pmatrix}\)

Y = Y

Pauli-Y atom representing the Y operator in a Pauli monomial or string. Matrix representation: \(\begin{pmatrix}0&-i\\i&0\end{pmatrix}\)

Z = Z

Pauli-Z atom representing the Z operator in a Pauli monomial or string. Matrix representation: \(\begin{pmatrix}1&0\\0&-1\end{pmatrix}\)