From 567541dcef96ea2da663464eaa0136d33bf8925d Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 12:03:55 +0400 Subject: [PATCH 01/10] basis encoding --- src/qibo/models/encodings.py | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index 3bcad17607..39b11240e7 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -1,6 +1,7 @@ """Module with functions that encode classical data into quantum circuits.""" import math +from typing import Optional, Union import numpy as np from scipy.stats import rv_continuous @@ -10,6 +11,54 @@ from qibo.models.circuit import Circuit +def comp_basis_encoder( + basis_element: Union[int, str, list, tuple], nqubits: Optional[int] = None +): + if not isinstance(basis_element, (int, str, list, tuple)): + raise_error( + TypeError, + "basis_element must be either type int or str or list or tuple, " + + f"but it is type {type(basis_element)}.", + ) + + if isinstance(basis_element, (str, list, tuple)): + if any(elem not in ["0", "1", 0, 1] for elem in basis_element): + raise_error(ValueError, "all elements must be 0 or 1.") + if len(basis_element) > nqubits: + raise_error( + ValueError, + f"nqubits ({nqubits}) must be >= len(basis_element) ({len(basis_element)}).", + ) + + if not isinstance(nqubits, int): + raise_error( + TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." + ) + + if nqubits is None: + if isinstance(basis_element, int): + raise_error( + ValueError, f"nqubits must be specified when basis_element is type int." + ) + else: + nqubits = len(basis_element) + + if isinstance(basis_element, int): + basis_element = f"{basis_element:0{nqubits}b}" + + if isinstance(basis_element, (str, tuple)): + basis_element = list(basis_element) + + basis_element = list(map(int, basis_element)) + + circuit = Circuit(nqubits) + for qubit, elem in enumerate(basis_element): + if elem == 1: + circuit.add(gates.X(qubit)) + + return circuit + + def unary_encoder(data, architecture: str = "tree"): """Creates circuit that performs the unary encoding of ``data``. From ef7f160c34cb607e9910b7a6d17e05f5b05ec69f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 17:30:02 +0400 Subject: [PATCH 02/10] fix bug --- src/qibo/models/encodings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index 39b11240e7..80eb6f86cf 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -30,7 +30,7 @@ def comp_basis_encoder( f"nqubits ({nqubits}) must be >= len(basis_element) ({len(basis_element)}).", ) - if not isinstance(nqubits, int): + if nqubits is not None and not isinstance(nqubits, int): raise_error( TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." ) From 578887760a1d1f631e2f16709f61afe763f0c107 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 17:30:09 +0400 Subject: [PATCH 03/10] tests --- tests/test_models_encodings.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index 18c7e2af96..d2dd2fbb15 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -5,7 +5,11 @@ import pytest from scipy.optimize import curve_fit -from qibo.models.encodings import unary_encoder, unary_encoder_random_gaussian +from qibo.models.encodings import ( + comp_basis_encoder, + unary_encoder, + unary_encoder_random_gaussian, +) def gaussian(x, a, b, c): @@ -13,6 +17,33 @@ def gaussian(x, a, b, c): return np.exp(a * x**2 + b * x + c) +@pytest.mark.parametrize("nqubits", [3]) +@pytest.mark.parametrize( + "basis_element", [5, "101", ["1", "0", "1"], [1, 0, 1], ("1", "0", "1"), (1, 0, 1)] +) +def test_comp_basis_encoder(backend, basis_element, nqubits): + with pytest.raises(TypeError): + circuit = comp_basis_encoder(2.3) + with pytest.raises(ValueError): + circuit = comp_basis_encoder("0b001") + with pytest.raises(ValueError): + circuit = comp_basis_encoder("001", nqubits=2) + with pytest.raises(TypeError): + circuit = comp_basis_encoder("001", nqubits=3.1) + with pytest.raises(ValueError): + circuit = comp_basis_encoder(3) + + zero = np.array([1, 0], dtype=complex) + one = np.array([0, 1], dtype=complex) + target = np.kron(one, np.kron(zero, one)) + target = backend.cast(target, dtype=target.dtype) + + state = comp_basis_encoder(basis_element, nqubits) + state = backend.execute_circuit(state).state() + + backend.assert_allclose(state, target) + + @pytest.mark.parametrize("architecture", ["tree", "diagonal"]) @pytest.mark.parametrize("nqubits", [8]) def test_unary_encoder(backend, nqubits, architecture): From 9bbd4e30bb42be321bc95286ef8edee4e9ddbabe Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 17:32:56 +0400 Subject: [PATCH 04/10] api reference --- 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 3ee49b39a9..1f6e65f071 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -247,6 +247,12 @@ Data Encoders We provide a family of algorithms that encode classical data into quantum circuits. +Computational Basis Encoder +""""""""""""""""""""""""""" + +.. autofunction:: qibo.models.encodings.comp_basis_encoder + + Unary Encoder """"""""""""" From 7348d75124a021ce342fbf4331567df6fe7cd52d Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 17:42:34 +0400 Subject: [PATCH 05/10] docstring --- src/qibo/models/encodings.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index 80eb6f86cf..2a6e8e0bdc 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -14,6 +14,22 @@ def comp_basis_encoder( basis_element: Union[int, str, list, tuple], nqubits: Optional[int] = None ): + """Creates circuit that performs encoding of bitstrings into computational basis states. + + Args: + basis_element (int or str or list or tuple): bitstring to be encoded. + If ``int``, ``nqubits`` must be specified. + If ``str``, must be composed of only :math:`0`s and :math:`1`s. + If ``list`` or ``tuple``, must be composed of :math:`0`s and + :math:`1`s as ``int`` or ``str``. + nqubits (int, optional): total number of qubits in the circuit. + If ``basis_element`` is ``int``, ``nqubits`` must be specified. + If ``nqubits`` is ``None``, ``nqubits`` defaults to length of ``basis_element``. + Defaults to ``None``. + + Returns: + :class:`qibo.models.circuit.Circuit`: circuit encoding computational basis element. + """ if not isinstance(basis_element, (int, str, list, tuple)): raise_error( TypeError, From b226374e8c05d34794c874c27f8bb02dc5bd160f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 18:14:11 +0400 Subject: [PATCH 06/10] fix coverage --- tests/test_models_encodings.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index d2dd2fbb15..dd78184669 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -17,7 +17,6 @@ def gaussian(x, a, b, c): return np.exp(a * x**2 + b * x + c) -@pytest.mark.parametrize("nqubits", [3]) @pytest.mark.parametrize( "basis_element", [5, "101", ["1", "0", "1"], [1, 0, 1], ("1", "0", "1"), (1, 0, 1)] ) @@ -38,7 +37,11 @@ def test_comp_basis_encoder(backend, basis_element, nqubits): target = np.kron(one, np.kron(zero, one)) target = backend.cast(target, dtype=target.dtype) - state = comp_basis_encoder(basis_element, nqubits) + if isinstance(basis_element, int): + state = comp_basis_encoder(basis_element, nqubits=3) + else: + state = comp_basis_encoder(basis_element) + state = backend.execute_circuit(state).state() backend.assert_allclose(state, target) From 267ef1a57ab7cbc203863dd52a102844b1752c30 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 18:28:54 +0400 Subject: [PATCH 07/10] fix test bug --- tests/test_models_encodings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index dd78184669..b102f746bf 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -20,7 +20,7 @@ def gaussian(x, a, b, c): @pytest.mark.parametrize( "basis_element", [5, "101", ["1", "0", "1"], [1, 0, 1], ("1", "0", "1"), (1, 0, 1)] ) -def test_comp_basis_encoder(backend, basis_element, nqubits): +def test_comp_basis_encoder(backend, basis_element): with pytest.raises(TypeError): circuit = comp_basis_encoder(2.3) with pytest.raises(ValueError): From 35d9f75f23163b384adf52e56db0021b6ed1575d Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 24 Jan 2024 19:52:48 +0400 Subject: [PATCH 08/10] fix bug --- src/qibo/models/encodings.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index 2a6e8e0bdc..a85024ad3c 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -40,11 +40,6 @@ def comp_basis_encoder( if isinstance(basis_element, (str, list, tuple)): if any(elem not in ["0", "1", 0, 1] for elem in basis_element): raise_error(ValueError, "all elements must be 0 or 1.") - if len(basis_element) > nqubits: - raise_error( - ValueError, - f"nqubits ({nqubits}) must be >= len(basis_element) ({len(basis_element)}).", - ) if nqubits is not None and not isinstance(nqubits, int): raise_error( From ab8e039c313c816ec007680ccf38a771199f60af Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 2 Feb 2024 09:22:51 +0400 Subject: [PATCH 09/10] add to doc --- doc/source/api-reference/qibo.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index e2b2568eda..5867c9b3ac 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -250,6 +250,26 @@ We provide a family of algorithms that encode classical data into quantum circui Computational Basis Encoder """"""""""""""""""""""""""" +Given a bitstring :math:`b` of length :math:`n`, this encoder generates of a layer of Pauli-:math:`X`` +gates that creates the quantum state :math:`|\,b\,\rangle`. + +For instance, the following two circuit generations are equivalent: + +.. testsetup:: + + from qibo import Circuit, gates + from qibo.models.encodings import comp_basis_encoder + +.. testcode:: + + b = "101" + circuit_1 = comp_basis_encoder(b) + + circuit_2 = Circuit(3) + circuit_2.add(gates.X(0)) + circuit_2.add(gates.X(2)) + + .. autofunction:: qibo.models.encodings.comp_basis_encoder From 8b85b6413e31232a695f53b94b599d7a501d713a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 2 Feb 2024 08:31:36 +0000 Subject: [PATCH 10/10] Update doc/source/api-reference/qibo.rst Co-authored-by: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> --- doc/source/api-reference/qibo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 5867c9b3ac..ad04550e1c 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -250,7 +250,7 @@ We provide a family of algorithms that encode classical data into quantum circui Computational Basis Encoder """"""""""""""""""""""""""" -Given a bitstring :math:`b` of length :math:`n`, this encoder generates of a layer of Pauli-:math:`X`` +Given a bitstring :math:`b` of length :math:`n`, this encoder generates a layer of Pauli-:math:`X` gates that creates the quantum state :math:`|\,b\,\rangle`. For instance, the following two circuit generations are equivalent: