Skip to content

Commit

Permalink
Merge branch 'master' into vqe_example
Browse files Browse the repository at this point in the history
  • Loading branch information
Simone-Bordoni committed Sep 16, 2024
2 parents ff9fab6 + 1b6eb8a commit b02222c
Show file tree
Hide file tree
Showing 17 changed files with 420 additions and 314 deletions.
5 changes: 3 additions & 2 deletions doc/source/api-reference/qibo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,8 @@ factor results in the mitigated Pauli expectation value :math:`\langle O\rangle_
.. math::
\langle O\rangle_{ideal} = \frac{\langle O\rangle_{noisy}}{\lambda}
.. autofunction:: qibo.models.error_mitigation.apply_randomized_readout_mitigation
This process can be implemented with the aforementioned
:func:`qibo.models.error_mitigation.apply_randomized_readout_mitigation`.


Zero Noise Extrapolation (ZNE)
Expand Down Expand Up @@ -2382,7 +2383,7 @@ Hellinger fidelity
Hellinger shot error
""""""""""""""""""""

.. autofunction:: qibo.quantum_info.hellinger_fidelity
.. autofunction:: qibo.quantum_info.hellinger_shot_error


Haar integral
Expand Down
2 changes: 0 additions & 2 deletions doc/source/code-examples/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,6 @@ For example, we can draw the QFT circuit for 5-qubits:
# new plot function based on matplotlib
from qibo.ui import plot_circuit

%matplotlib inline

# create a 5-qubits QFT circuit
c = QFT(5)
c.add(gates.M(qubit) for qubit in range(2))
Expand Down
3 changes: 2 additions & 1 deletion examples/shor/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,9 @@ def quantum_order_finding_semiclassical(N, a):
circuit.add(gates.U1(q_reg, -angle))
circuit.add(gates.H(q_reg))
results.append(circuit.add(gates.M(q_reg, collapse=True)))
circuit.add(gates.M(q_reg))

circuit() # execute
circuit(nshots=1) # execute
s = sum(int(r.symbols[0].outcome()) * (2**i) for i, r in enumerate(results))
print(f"The quantum circuit measures s = {s}.\n")
return s
Expand Down
2 changes: 1 addition & 1 deletion src/qibo/backends/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def execute_circuit(
def execute_circuits(
self, circuits, initial_states=None, nshots=None
): # pragma: no cover
"""Execute multiple :class:`qibo.models.circuit.Circuit`s in parallel."""
"""Execute multiple :class:`qibo.models.circuit.Circuit` in parallel."""
raise_error(NotImplementedError)

@abc.abstractmethod
Expand Down
6 changes: 3 additions & 3 deletions src/qibo/backends/clifford.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ def calculate_frequencies(self, samples):
return collections.Counter(dict(zip(res, counts)))

def zero_state(self, nqubits: int):
"""Construct the zero state |00...00>.
"""Construct the zero state :math`\\ket{00...00}`.
Args:
nqubits (int): Number of qubits.
nqubits (int): number of qubits.
Returns:
(ndarray): Symplectic matrix for the zero state.
ndarray: Symplectic matrix for the zero state.
"""
identity = self.np.eye(nqubits)
symplectic_matrix = self.np.zeros(
Expand Down
7 changes: 5 additions & 2 deletions src/qibo/gates/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ def to_choi(self, nqubits: Optional[int] = None, order: str = "row", backend=Non
of the Kraus channel :math:`\\{K_{\\alpha}\\}_{\\alpha}`.
.. math::
\\mathcal{E} = \\sum_{\\alpha} \\, |K_{\\alpha}\\rangle\\rangle
\\langle\\langle K_{\\alpha}|
\\mathcal{E} = \\sum_{\\alpha} \\, |K_{\\alpha})(K_{\\alpha}| \\, ,
where :math:`|K_{\\alpha})` is the vectorization of the Kraus operator
:math:`K_{\\alpha}`.
For a definition of vectorization, see :func:`qibo.quantum_info.vectorization`.
Args:
nqubits (int, optional): total number of qubits to be considered
Expand Down
13 changes: 6 additions & 7 deletions src/qibo/gates/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,26 @@ class M(Gate):
If the qubits to measure are held in an iterable (eg. list) the ``*``
operator can be used, for example ``gates.M(*[0, 1, 4])`` or
``gates.M(*range(5))``.
register_name (str): Optional name of the register to distinguish it
register_name (str, optional): Optional name of the register to distinguish it
from other registers when used in circuits.
collapse (bool): Collapse the state vector after the measurement is
performed. Can be used only for single shot measurements.
If ``True`` the collapsed state vector is returned. If ``False``
the measurement result is returned.
basis (:class:`qibo.gates.Gate`, str, list): Basis to measure.
basis (:class:`qibo.gates.Gate` or str or list, optional): Basis to measure.
Can be either:
- a qibo gate
- the string representing the gate
- a callable that accepts a qubit, for example: ``lambda q: gates.RX(q, 0.2)``
- a list of the above, if a different basis will be used for each
measurement qubit.
Default is Z.
p0 (dict): Optional bitflip probability map. Can be:
- a list of the above, if a different basis will be used for each measurement qubit.
Defaults is to :class:`qibo.gates.Z`.
p0 (dict, optional): bitflip probability map. Can be:
A dictionary that maps each measured qubit to the probability
that it is flipped, a list or tuple that has the same length
as the tuple of measured qubits or a single float number.
If a single float is given the same probability will be used
for all qubits.
p1 (dict): Optional bitflip probability map for asymmetric bitflips.
p1 (dict, optional): bitflip probability map for asymmetric bitflips.
Same as ``p0`` but controls the 1->0 bitflip probability.
If ``p1`` is ``None`` then ``p0`` will be used both for 0->1 and
1->0 bitflips.
Expand Down
10 changes: 5 additions & 5 deletions src/qibo/models/error_mitigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,24 +658,24 @@ def apply_randomized_readout_mitigation(
nshots (int, optional): number of shots. Defaults to :math:`10000`.
ncircuits (int, optional): number of randomized circuits. Each of them uses
``int(nshots / ncircuits)`` shots. Defaults to 10.
qubit_map (list, optional): the qubit map. If None, a list of range of circuit's qubits is used.
Defaults to ``None``.
qubit_map (list, optional): the qubit map. If ``None``, a list of range of circuit's
qubits is used. Defaults to ``None``.
seed (int or :class:`numpy.random.Generator`, optional): Either a generator of random
numbers or a fixed seed to initialize a generator. If ``None``, initializes
a generator with a random seed. Default: ``None``.
backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used
in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`.
Defaults to ``None``.
Return:
Returns:
:class:`qibo.measurements.CircuitResult`: the state of the input circuit with
mitigated frequencies.
Reference:
References:
1. Ewout van den Berg, Zlatko K. Minev et al,
*Model-free readout-error mitigation for quantum expectation values*.
`arXiv:2012.09738 [quant-ph] <https://arxiv.org/abs/2012.09738>`_.
`arXiv:2012.09738 [quant-ph] <https://arxiv.org/abs/2012.09738>`_.
"""
from qibo import Circuit # pylint: disable=import-outside-toplevel
from qibo.quantum_info import ( # pylint: disable=import-outside-toplevel
Expand Down
40 changes: 21 additions & 19 deletions src/qibo/quantum_info/basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ def pauli_basis(
vectorize (bool, optional): If ``False``, returns a nested array with
all Pauli matrices. If ``True``, retuns an array where every
row is a vectorized Pauli matrix. Defaults to ``False``.
sparse (bool, optional) If ``True``, retuns Pauli basis in a sparse
representation. Default is ``False``.
sparse (bool, optional): If ``True``, retuns Pauli basis in a sparse
representation. Defaults to ``False``.
order (str, optional): If ``"row"``, vectorization of Pauli basis is
performed row-wise. If ``"column"``, vectorization is performed
column-wise. If ``"system"``, system-wise vectorization is
performed. If ``vectorization=False``, then ``order=None`` is
forced. Default is ``None``.
forced. Defaults to ``None``.
pauli_order (str, optional): corresponds to the order of 4 single-qubit
Pauli elements. Default is "IXYZ".
Pauli elements. Defaults to ``"IXYZ"``.
backend (:class:`qibo.backends.abstract.Backend`, optional): backend
to be used in the execution. If ``None``, it uses
:class:`qibo.backends.GlobalBackend`. Defaults to ``None``.
Expand Down Expand Up @@ -148,15 +148,12 @@ def comp_basis_to_pauli(
The unitary :math:`U` is given by
.. math::
U = \\sum_{k = 0}^{d^{2} - 1} \\, \\ketbra{k}{P_{k}} \\,\\, ,
U = \\sum_{k = 0}^{d^{2} - 1} \\, |k)(P_{k}| \\,\\, ,
where :math:`\\ket{P_{k}}` is the system-vectorization of the :math:`k`-th
Pauli operator :math:`P_{k}`, and :math:`\\ket{k}` is the computational
basis element.
When converting a state :math:`\\ket{\\rho}` to its Pauli-Liouville
representation :math:`\\ket{\\rho'}`, one should use ``order="system"``
in :func:`vectorization`.
where :math:`|P_{k})` is the vectorization of the :math:`k`-th
Pauli operator :math:`P_{k}`, and :math:`|k)` is the vectorization
of the :math:`k`-th computational basis element.
For a definition of vectorization, see :func:`qibo.quantum_info.vectorization`.
Example:
.. code-block:: python
Expand All @@ -174,13 +171,13 @@ def comp_basis_to_pauli(
normalize (bool, optional): If ``True``, converts to the
Pauli basis. Defaults to ``False``.
sparse (bool, optional): If ``True``, returns unitary matrix in
sparse representation. Default is ``False``.
sparse representation. Defaults to ``False``.
order (str, optional): If ``"row"``, vectorization of Pauli basis is
performed row-wise. If ``"column"``, vectorization is performed
column-wise. If ``"system"``, system-wise vectorization is
performed. Default is ``"row"``.
performed. Defaults to ``"row"``.
pauli_order (str, optional): corresponds to the order of 4 single-qubit
Pauli elements. Default is "IXYZ".
Pauli elements. Defaults to ``"IXYZ"``.
backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be
used in the execution. If ``None``, it uses
:class:`qibo.backends.GlobalBackend`. Defaults to ``None``.
Expand Down Expand Up @@ -237,20 +234,25 @@ def pauli_to_comp_basis(
The unitary :math:`U` is given by
.. math::
U = \\sum_{k = 0}^{d^{2} - 1} \\, \\ketbra{P_{k}}{b_{k}} \\, .
U = \\sum_{k = 0}^{d^{2} - 1} \\, |P_{k})(b_{k}| \\, ,
where :math:`|P_{k})` is the vectorization of the :math:`k`-th
Pauli operator :math:`P_{k}`, and :math:`|k)` is the vectorization
of the :math:`k`-th computational basis element.
For a definition of vectorization, see :func:`qibo.quantum_info.vectorization`.
Args:
nqubits (int): number of qubits.
normalize (bool, optional): If ``True``, converts to the
Pauli basis. Defaults to ``False``.
sparse (bool, optional): If ``True``, returns unitary matrix in
sparse representation. Default is ``False``.
sparse representation. Defaults to ``False``.
order (str, optional): If ``"row"``, vectorization of Pauli basis is
performed row-wise. If ``"column"``, vectorization is performed
column-wise. If ``"system"``, system-wise vectorization is
performed. Default is ``"row"``.
performed. Defaults to ``"row"``.
pauli_order (str, optional): corresponds to the order of 4 single-qubit
Pauli elements. Default is "IXYZ".
Pauli elements. Defaults to ``"IXYZ"``.
backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be
used in the execution. If ``None``, it uses
:class:`qibo.backends.GlobalBackend`. Defaults to ``None``.
Expand Down
14 changes: 7 additions & 7 deletions src/qibo/quantum_info/clifford.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,16 @@ def frequencies(self, binary: bool = True, registers: bool = False):
of times each measured value/bitstring appears.
If ``binary`` is ``True``
the keys of the `Counter` are in binary form, as strings of
:math:`0`s and :math`1`s.
the keys of the :class:`collections.Counter` are in binary form,
as strings of :math:`0` and :math`1`.
If ``binary`` is ``False``
the keys of the ``Counter`` are integers.
the keys of the :class:`collections.Counter` are integers.
If ``registers`` is ``True``
a `dict` of `Counter` s is returned where keys are the name of
each register.
a `dict` of :class:`collections.Counter` is returned where keys are
the name of each register.
If ``registers`` is ``False``
a single ``Counter`` is returned which contains samples from all
the measured qubits, independently of their registers.
a single :class:`collections.Counter` is returned which contains samples
from all the measured qubits, independently of their registers.
"""
measured_qubits = self.measurement_gate.target_qubits
freq = self._backend.calculate_frequencies(self.samples(False))
Expand Down
4 changes: 2 additions & 2 deletions src/qibo/quantum_info/entropies.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen
For probabilities :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, it is defined as
..math::
.. math::
D(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\sum_{x} \\, \\mathbf{p}(x) \\,
\\log\\left( \\frac{\\mathbf{p}(x)}{\\mathbf{q}(x)} \\right) \\, .
Expand Down Expand Up @@ -680,7 +680,7 @@ def relative_renyi_entropy(
This is known as the `min-relative entropy <https://arxiv.org/abs/1310.7178>`_.
.. note::
Function raises ``NotImplementedError`` when ``target`` :math:`sigma`
Function raises ``NotImplementedError`` when ``target`` :math:`\\sigma`
is a pure state and :math:`\\alpha > 1`. This is due to the fact that
it is not possible to calculate :math:`\\sigma^{1 - \\alpha}` when
:math:`\\alpha > 1` and :math:`\\sigma` is a projector, i.e. a singular matrix.
Expand Down
38 changes: 22 additions & 16 deletions src/qibo/quantum_info/superoperator_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@


def vectorization(state, order: str = "row", backend=None):
"""Returns state :math:`\\rho` in its Liouville
representation :math:`|\\rho\\rangle\\rangle`.
"""Returns state :math:`\\rho` in its Liouville representation :math:`|\\rho)`.
If ``order="row"``, then:
.. math::
|\\rho\\rangle\\rangle = \\sum_{k, l} \\, \\rho_{kl} \\, \\ket{k} \\otimes \\ket{l}
|\\rho) = \\sum_{k, l} \\, \\rho_{kl} \\, \\ket{k} \\otimes \\ket{l}
If ``order="column"``, then:
.. math::
|\\rho\\rangle\\rangle = \\sum_{k, l} \\, \\rho_{kl} \\, \\ket{l} \\otimes \\ket{k}
|\\rho) = \\sum_{k, l} \\, \\rho_{kl} \\, \\ket{l} \\otimes \\ket{k}
Args:
state: state vector or density matrix.
Expand Down Expand Up @@ -88,12 +87,12 @@ def vectorization(state, order: str = "row", backend=None):

def unvectorization(state, order: str = "row", backend=None):
"""Returns state :math:`\\rho` from its Liouville
representation :math:`|\\rho\\rangle\\rangle`. This operation is
representation :math:`|\\rho)`. This operation is
the inverse function of :func:`vectorization`, i.e.
.. math::
\\begin{align}
\\rho &= \\text{unvectorization}(|\\rho\\rangle\\rangle) \\nonumber \\\\
\\rho &= \\text{unvectorization}(|\\rho)) \\nonumber \\\\
&= \\text{unvectorization}(\\text{vectorization}(\\rho)) \\nonumber
\\end{align}
Expand Down Expand Up @@ -152,9 +151,9 @@ def to_choi(channel, order: str = "row", backend=None):
"""Converts quantum ``channel`` :math:`U` to its Choi representation :math:`\\Lambda`.
.. math::
\\Lambda = | U \\rangle\\rangle \\langle\\langle U | \\, ,
\\Lambda = | U ) ( U | \\, ,
where :math:`| \\cdot \\rangle\\rangle` is the :func:`qibo.quantum_info.vectorization`
where :math:`| \\cdot )` is the :func:`qibo.quantum_info.vectorization`
operation.
Args:
Expand Down Expand Up @@ -376,7 +375,9 @@ def choi_to_kraus(
.. math::
\\Lambda = \\sum_{\\alpha} \\, \\lambda_{\\alpha}^{2} \\,
|\\tilde{K}_{\\alpha}\\rangle\\rangle \\langle\\langle \\tilde{K}_{\\alpha}| \\, .
|\\tilde{K}_{\\alpha})(\\tilde{K}_{\\alpha}| \\, .
where :math:`|\\cdot)` is the :func:`qibo.quantum_info.vectorization` operation.
This is the spectral decomposition of :math:`\\Lambda`, Hence, the set
:math:`\\{\\lambda_{\\alpha}, \\, \\tilde{K}_{\\alpha}\\}_{\\alpha}`
Expand All @@ -385,7 +386,7 @@ def choi_to_kraus(
.. math::
K_{\\alpha} = \\lambda_{\\alpha} \\,
\\text{unvectorization}(|\\tilde{K}_{\\alpha}\\rangle\\rangle) \\, .
\\text{unvectorization}(|\\tilde{K}_{\\alpha})) \\, .
If :math:`\\mathcal{E}` is not CP, then spectral composition is replaced by
a singular value decomposition (SVD), i.e.
Expand Down Expand Up @@ -638,7 +639,11 @@ def kraus_to_choi(kraus_ops, order: str = "row", backend=None):
of quantum channel to its Choi representation :math:`\\Lambda`.
.. math::
\\Lambda = \\sum_{\\alpha} \\, |K_{\\alpha}\\rangle\\rangle \\langle\\langle K_{\\alpha}|
\\Lambda = \\sum_{\\alpha} \\, |K_{\\alpha})( K_{\\alpha}|
where :math:`|K_{\\alpha})` is the vectorization of the Kraus operator
:math:`K_{\\alpha}`.
For a definition of vectorization, see :func:`qibo.quantum_info.vectorization`.
Args:
kraus_ops (list): List of Kraus operators as pairs ``(qubits, Ak)``
Expand Down Expand Up @@ -757,10 +762,11 @@ def kraus_to_chi(
of quantum channel to its :math:`\\chi`-matrix representation.
.. math::
\\chi = \\sum_{\\alpha} \\, |c_{\\alpha}\\rangle\\rangle \\langle\\langle c_{\\alpha}|,
\\chi = \\sum_{\\alpha} \\, |c_{\\alpha})( c_{\\alpha}|,
where :math:`|c_{\\alpha}\\rangle\\rangle \\cong |K_{\\alpha}\\rangle\\rangle`
in Pauli-Liouville basis.
where :math:`|c_{\\alpha}) \\cong |K_{\\alpha})` in Pauli-Liouville basis,
and :math:`| \\cdot )` is the :func:`qibo.quantum_info.vectorization`
operation.
Args:
kraus_ops (list): List of Kraus operators as pairs ``(qubits, Ak)``
Expand Down Expand Up @@ -2130,8 +2136,6 @@ def _reshuffling(super_op, order: str = "row", backend=None):
Returns:
ndarray: Choi (Liouville) representation of the quantum channel.
"""
super_op = backend.cast(super_op)

if not isinstance(order, str):
raise_error(TypeError, f"order must be type str, but it is type {type(order)}.")

Expand All @@ -2150,6 +2154,8 @@ def _reshuffling(super_op, order: str = "row", backend=None):

backend = _check_backend(backend)

super_op = backend.cast(super_op, dtype=super_op.dtype)

dim = np.sqrt(super_op.shape[0])

if (
Expand Down
Loading

0 comments on commit b02222c

Please sign in to comment.