Skip to content

Commit

Permalink
Merge branch 'lossf' of https://github.com/qiboteam/qibo into lossf
Browse files Browse the repository at this point in the history
  • Loading branch information
WanderingMike committed Dec 13, 2023
2 parents 90f6517 + 53e75c5 commit 8d2a250
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ dmypy.json

# tmp files
tmp/
tmp.npy

# Mac
.DS_Store
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repos:
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.1
hooks:
- id: isort
args: ["--profile", "black"]
Expand Down
8 changes: 7 additions & 1 deletion doc/source/api-reference/qibo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ types:

- the **heuristics** optimizers: an evolutionary strategy (Covariance matrix adaptation evolution strategy (CMA-ES)), for which we rely on the `cmaes`_ packages and a Basin-Hopping algorithm implementation provided by Scipy as `scipy.optimize.basinhopping`_. These methods are global and, as in the case of many meta-heuristic optimizers they can be as versatile as they are computationally intensive;

- the **gradient based** optimizers built on top of `Tensorflow`_ implementation. This `TensorflowSGD` optimization routine has to be used activating the `tensorflow` backend.
- the **gradient based** optimizers built on top of `Tensorflow`_ implementation. This `TensorflowSGD` optimization routine has to be used activating the `tensorflow` backend.

.. _`scipy.optimize.minimize`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
.. _`scipy.optimize.basinhopping`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.basinhopping.html
Expand Down Expand Up @@ -1546,6 +1546,12 @@ Expressibility of parameterized quantum circuits
.. autofunction:: qibo.quantum_info.expressibility


Frame Potential
"""""""""""""""

.. autofunction:: qibo.quantum_info.frame_potential


Random Ensembles
^^^^^^^^^^^^^^^^

Expand Down
9 changes: 9 additions & 0 deletions src/qibo/gates/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ def to_pauli_liouville(

return super_op

def matrix(self, backend=None):
""""""
raise_error(
NotImplementedError,
"`matrix` method not defined for Channels. "
+ "Please use one of the following methods: "
+ "`to_choi` or `to_liouville` or `to_pauli_liouville`.",
)


class KrausChannel(Channel):
"""General channel defined by arbitrary Kraus operators.
Expand Down
78 changes: 77 additions & 1 deletion src/qibo/quantum_info/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ def expressibility(
Defaults to ``None``.
Returns:
float: Entangling capability.
float: Expressibility of parametrized circuit.
"""

if isinstance(power_t, int) is False:
Expand Down Expand Up @@ -1146,6 +1146,82 @@ def expressibility(
return fid


def frame_potential(
circuit,
power_t: int,
samples: int = None,
backend=None,
):
"""Returns the frame potential of a parametrized circuit under uniform sampling of the parameters.
For :math:`n` qubits and moment :math:`t`, the frame potential
:math:`\\mathcal{F}_{\\mathcal{U}}^{(t)}` if given by [1]
.. math::
\\mathcal{F}_{\\mathcal{U}}^{(t)} = \\int_{U,V \\in \\mathcal{U}} \\,
\\text{d}U \\, \\text{d}V \\, \\text{abs}\\bigl[\\text{tr}(U^{\\dagger} \\, V)\\bigr]^{2t} \\, ,
where :math:`\\mathcal{U}` is the group of unitaries defined by the parametrized circuit.
The frame potential is approximated by the average
.. math::
\\mathcal{F}_{\\mathcal{U}}^{(t)} \\approx \\frac{1}{N} \\,
\\sum_{k=1}^{N} \\, \\text{abs}\\bigl[ \\text{tr}(U_{k}^{\\dagger} \\, V_{k})\\bigr]^{2t} \\, ,
where :math:`N` is the number of ``samples``.
Args:
circuit (:class:`qibo.models.circuit.Circuit`): Parametrized circuit.
power_t (int): power that defines the :math:`t`-design.
samples (int): number of samples to estimate the integral.
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``.
Returns:
float: Frame potential of the parametrized circuit.
References:
1. M. Liu *et al.*, *Estimating the randomness of quantum circuit ensembles up to 50 qubits*.
`arXiv:2205.09900 [quant-ph] <https://arxiv.org/abs/2205.09900>`_.
"""
if not isinstance(power_t, int):
raise_error(
TypeError, f"power_t must be type int, but it is type {type(power_t)}."
)

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

if backend is None: # pragma: no cover
backend = GlobalBackend()

nqubits = circuit.nqubits
dim = 2**nqubits

potential = 0
for _ in range(samples):
unitary_1 = circuit.copy()
params_1 = np.random.uniform(-np.pi, np.pi, circuit.trainable_gates.nparams)
unitary_1.set_parameters(params_1)
unitary_1 = unitary_1.unitary(backend) / np.sqrt(dim)

for _ in range(samples):
unitary_2 = circuit.copy()
params_2 = np.random.uniform(-np.pi, np.pi, circuit.trainable_gates.nparams)
unitary_2.set_parameters(params_2)
unitary_2 = unitary_2.unitary(backend) / np.sqrt(dim)

potential += np.abs(
np.trace(np.transpose(np.conj(unitary_1)) @ unitary_2)
) ** (2 * power_t)

return potential / samples**2


def _check_hermitian_or_not_gpu(matrix, backend=None):
"""Checks if a given matrix is Hermitian and whether
the backend is neither :class:`qibojit.backends.CupyBackend`
Expand Down
5 changes: 3 additions & 2 deletions src/qibo/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@ def state(self, numpy: bool = False):
"""State's tensor representation as a backend tensor.
Args:
numpy (bool, optional): If ``True`` the returned tensor will be a numpy array,
numpy (bool, optional): If ``True`` the returned tensor will be a ``numpy`` array,
otherwise it will follow the backend tensor type.
Defaults to ``False``.
Returns:
The state in the computational basis.
"""
if numpy:
return np.array(self._state)
return np.array(self._state.tolist())

return self._state

def probabilities(self, qubits: Optional[Union[list, set]] = None):
Expand Down
2 changes: 2 additions & 0 deletions tests/test_gates_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def test_general_channel(backend):
with pytest.raises(NotImplementedError):
state = random_statevector(2**2, backend=backend)
channel1.apply(backend, state, 2)
with pytest.raises(NotImplementedError):
channel1.matrix(backend)


def test_controlled_by_channel_error():
Expand Down
28 changes: 28 additions & 0 deletions tests/test_quantum_info_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
entropy,
expressibility,
fidelity,
frame_potential,
gate_error,
hilbert_schmidt_distance,
impurity,
Expand Down Expand Up @@ -649,3 +650,30 @@ def test_expressibility(backend):
expr_3 = expressibility(c3, t, samples, backend=backend)

backend.assert_allclose(expr_1 < expr_2 < expr_3, True)


@pytest.mark.parametrize("samples", [int(1e2)])
@pytest.mark.parametrize("power_t", [2])
@pytest.mark.parametrize("nqubits", [2, 3, 4])
def test_frame_potential(backend, nqubits, power_t, samples):
depth = int(np.ceil(nqubits * power_t))

circuit = Circuit(nqubits)
circuit.add(gates.U3(q, 0.0, 0.0, 0.0) for q in range(nqubits))
for _ in range(depth):
circuit.add(gates.CNOT(q, q + 1) for q in range(nqubits - 1))
circuit.add(gates.U3(q, 0.0, 0.0, 0.0) for q in range(nqubits))

with pytest.raises(TypeError):
frame_potential(circuit, power_t="2", backend=backend)
with pytest.raises(TypeError):
frame_potential(circuit, 2, samples="1000", backend=backend)

dim = 2**nqubits
potential_haar = 2 / dim**4

potential = frame_potential(
circuit, power_t=power_t, samples=samples, backend=backend
)

backend.assert_allclose(potential, potential_haar, rtol=1e-2, atol=1e-2)

0 comments on commit 8d2a250

Please sign in to comment.