From a7736f3df30c0e6799fe19ec02046941d28b748c Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 24 Oct 2023 15:48:47 +0400 Subject: [PATCH 1/8] api doc --- doc/source/api-reference/qibo.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 33947014cb..7c0c3d3c41 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1443,6 +1443,12 @@ Random Ensembles Functions that can generate random quantum objects. +Haar-random :math:`U_{3}` +""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.uniform_sampling_U3 + + Random Gaussian matrix """""""""""""""""""""" From c7bbd734e86416ddde8297ac90e37d21de878cf9 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 24 Oct 2023 15:48:59 +0400 Subject: [PATCH 2/8] function --- src/qibo/quantum_info/random_ensembles.py | 61 +++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index e13c981577..8c9d4f8379 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -4,6 +4,7 @@ from typing import Optional, Union import numpy as np +from scipy.stats import rv_continuous from qibo import Circuit, gates from qibo.backends import GlobalBackend, NumpyBackend @@ -19,6 +20,66 @@ ) +class _probability_distribution_sin(rv_continuous): + def _pdf(self, theta: float): + return 0.5 * np.sin(theta) + + def _cdf(self, theta: float): + return np.sin(theta / 2) ** 2 + + def _ppf(self, theta: float): + return 2 * np.arcsin(np.sqrt(theta)) + + +def uniform_sampling_U3(ngates: int, seed=None, backend=None): + """Samples parameters for Haar-random :math:`U_{3}`s (:class:`qibo.gates.U3`). + + Args: + ngates (int): Total number of :math:`U_{3}`s to be sampled. + 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``. + + Returns: + (ndarray): array of shape (``ngates``, :math:`3`). + """ + if not isinstance(ngates, int): + raise_error( + TypeError, f"ngates must be type int, but it is type {type(ngates)}." + ) + elif ngates <= 0: + raise_error(ValueError, f"ngates must be non-negative, but it is {ngates}.") + + if ( + seed is not None + and not isinstance(seed, int) + and not isinstance(seed, np.random.Generator) + ): + raise_error( + TypeError, "seed must be either type int or numpy.random.Generator." + ) + + if backend is None: # pragma: no cover + backend = GlobalBackend() + + local_state = ( + np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed + ) + + sampler = _probability_distribution_sin(a=0, b=np.pi, seed=local_state) + phases = local_state.random((ngates, 3)) + phases[:, 0] = sampler.rvs(size=len(phases[:, 0])) + phases[:, 1] = phases[:, 1] * 2 * np.pi + phases[:, 2] = phases[:, 2] * 2 * np.pi + + phases = backend.cast(phases, dtype=phases.dtype) + + return phases + + def random_gaussian_matrix( dims: int, rank: Optional[int] = None, From 3c01e00150416057d2ea0527c7bf230dbe82b252 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 24 Oct 2023 15:49:05 +0400 Subject: [PATCH 3/8] test --- tests/test_quantum_info_random.py | 40 +++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 5f7331dad9..9273741b72 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from qibo import matrices +from qibo import Circuit, gates, matrices from qibo.config import PRECISION_TOL from qibo.quantum_info.metrics import purity from qibo.quantum_info.random_ensembles import ( @@ -19,10 +19,46 @@ random_statevector, random_stochastic_matrix, random_unitary, + uniform_sampling_U3, ) -@pytest.mark.parametrize("seed", [None, 10, np.random.Generator(np.random.MT19937(10))]) +@pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) +def test_uniform_sampling_U3(backend, seed): + with pytest.raises(TypeError): + uniform_sampling_U3("1", seed=seed, backend=backend) + with pytest.raises(ValueError): + uniform_sampling_U3(0, seed=seed, backend=backend) + with pytest.raises(TypeError): + uniform_sampling_U3(2, seed="1", backend=backend) + + X = backend.cast(matrices.X, dtype=matrices.X.dtype) + Y = backend.cast(matrices.Y, dtype=matrices.Y.dtype) + Z = backend.cast(matrices.Z, dtype=matrices.Z.dtype) + + ngates = int(1e4) + phases = uniform_sampling_U3(ngates, seed=seed, backend=backend) + + expectation_values = [] + for row in phases: + circuit = Circuit(1) + circuit.add(gates.U3(0, *row)) + state = backend.execute_circuit(circuit).state() + + expectation_values.append( + [ + np.conj(state) @ X @ state, + np.conj(state) @ Y @ state, + np.conj(state) @ Z @ state, + ] + ) + expectation_values = np.mean(expectation_values, axis=0) + + backend.assert_allclose(expectation_values[0], expectation_values[1], atol=1e-1) + backend.assert_allclose(expectation_values[0], expectation_values[2], atol=1e-1) + + +@pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) def test_random_gaussian_matrix(backend, seed): with pytest.raises(TypeError): dims = np.array([2]) From e1940d870644c9234d9d66fcd12207ec5ffe17db Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 24 Oct 2023 18:12:19 +0400 Subject: [PATCH 4/8] fix coverage --- tests/test_quantum_info_random.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 9273741b72..a11dc67a0b 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -20,6 +20,7 @@ random_stochastic_matrix, random_unitary, uniform_sampling_U3, + _probability_distribution_sin, ) @@ -39,6 +40,7 @@ def test_uniform_sampling_U3(backend, seed): ngates = int(1e4) phases = uniform_sampling_U3(ngates, seed=seed, backend=backend) + # expectation values in the 3 directions should be the same expectation_values = [] for row in phases: circuit = Circuit(1) @@ -57,6 +59,10 @@ def test_uniform_sampling_U3(backend, seed): backend.assert_allclose(expectation_values[0], expectation_values[1], atol=1e-1) backend.assert_allclose(expectation_values[0], expectation_values[2], atol=1e-1) + # execution for coverage + sampler = _probability_distribution_sin(a=0, b=np.pi, seed=seed) + sampler.pdf(1) + sampler.cdf(1) @pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) def test_random_gaussian_matrix(backend, seed): From 89fcd30968ca54c574ac530002482e4a46ae1bbd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:12:47 +0000 Subject: [PATCH 5/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_quantum_info_random.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index a11dc67a0b..066f06c952 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -9,6 +9,7 @@ from qibo.config import PRECISION_TOL from qibo.quantum_info.metrics import purity from qibo.quantum_info.random_ensembles import ( + _probability_distribution_sin, random_clifford, random_density_matrix, random_gaussian_matrix, @@ -20,7 +21,6 @@ random_stochastic_matrix, random_unitary, uniform_sampling_U3, - _probability_distribution_sin, ) @@ -64,6 +64,7 @@ def test_uniform_sampling_U3(backend, seed): sampler.pdf(1) sampler.cdf(1) + @pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) def test_random_gaussian_matrix(backend, seed): with pytest.raises(TypeError): From beab337b1fc29df1cd91aa4e8e9148e2afc433a5 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 1 Nov 2023 05:22:12 +0000 Subject: [PATCH 6/8] Update tests/test_quantum_info_random.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- tests/test_quantum_info_random.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 066f06c952..8dbca55d07 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -54,7 +54,8 @@ def test_uniform_sampling_U3(backend, seed): np.conj(state) @ Z @ state, ] ) - expectation_values = np.mean(expectation_values, axis=0) +expectation_values = backend.cast(expectation_values) +expectation_values = np.mean(expectation_values, axis=0) backend.assert_allclose(expectation_values[0], expectation_values[1], atol=1e-1) backend.assert_allclose(expectation_values[0], expectation_values[2], atol=1e-1) From 0c242a123a01ad5610643d0c2262a54a67ee3983 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 1 Nov 2023 09:27:13 +0400 Subject: [PATCH 7/8] fix identation --- tests/test_quantum_info_random.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 8dbca55d07..b0d615fe09 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -54,8 +54,8 @@ def test_uniform_sampling_U3(backend, seed): np.conj(state) @ Z @ state, ] ) -expectation_values = backend.cast(expectation_values) -expectation_values = np.mean(expectation_values, axis=0) + expectation_values = backend.cast(expectation_values) + expectation_values = np.mean(expectation_values, axis=0) backend.assert_allclose(expectation_values[0], expectation_values[1], atol=1e-1) backend.assert_allclose(expectation_values[0], expectation_values[2], atol=1e-1) From e550b35bbf456ff9e818a6ce54989c6cfd33c271 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 1 Nov 2023 16:11:00 +0000 Subject: [PATCH 8/8] Update tests/test_quantum_info_random.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- tests/test_quantum_info_random.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index b0d615fe09..7704970cc6 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -43,6 +43,7 @@ def test_uniform_sampling_U3(backend, seed): # expectation values in the 3 directions should be the same expectation_values = [] for row in phases: + row = [float(phase) for phase in row] circuit = Circuit(1) circuit.add(gates.U3(0, *row)) state = backend.execute_circuit(circuit).state()