From 035836a9aadf1559f2b32796f835571142c42b6a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 20 Sep 2024 14:34:48 +0400 Subject: [PATCH 01/16] backup --- src/qibo/quantum_info/linalg_operations.py | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index ae87ba4e12..ccb72e9be5 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -1,5 +1,6 @@ """Module with common linear algebra operations for quantum information.""" +# %% import math from typing import List, Tuple, Union @@ -196,3 +197,32 @@ def matrix_exponentiation( backend = _check_backend(backend) return backend.calculate_matrix_exp(phase, matrix, eigenvectors, eigenvalues) + + +def schmidt_decomposition(state, backend=None): + decomposition = state + return decomposition + + +# %% +import numpy as np + +from qibo import set_backend +from qibo.backends import NumpyBackend +from qibo.quantum_info import random_statevector + +set_backend("numpy") +backend = NumpyBackend() + +#%% +nqubits = 2 +dims = 2**nqubits + +new_dims = int(np.sqrt(dims)) + +state = random_statevector(dims, backend=backend) + +#%% +new_state = state.reshape(-1, new_dims) +U, S, V = np.linalg.svd(new_state) + From 858ed923ec10acf2ba7dbc99118c767caad91ae8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 4 Oct 2024 04:55:22 +0000 Subject: [PATCH 02/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/linalg_operations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 3275779a24..8eb120edae 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -232,7 +232,7 @@ def schmidt_decomposition(state, backend=None): set_backend("numpy") backend = NumpyBackend() -#%% +# %% nqubits = 2 dims = 2**nqubits @@ -240,6 +240,6 @@ def schmidt_decomposition(state, backend=None): state = random_statevector(dims, backend=backend) -#%% +# %% new_state = state.reshape(-1, new_dims) U, S, V = np.linalg.svd(new_state) From bb290e50f1ca7e5e49ddfd4c228462bf8b0c29b5 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 4 Oct 2024 12:50:00 +0400 Subject: [PATCH 03/16] backup --- src/qibo/quantum_info/linalg_operations.py | 36 +++++++++------------- tests/test_quantum_info_operations.py | 15 +++++++++ 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 8eb120edae..488fecfc0e 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -1,6 +1,5 @@ """Module with common linear algebra operations for quantum information.""" -# %% import math from typing import List, Tuple, Union @@ -217,29 +216,22 @@ def matrix_power(matrix, power: Union[float, int], backend=None): return backend.calculate_matrix_power(matrix, power) -def schmidt_decomposition(state, backend=None): - decomposition = state - return decomposition - - -# %% -import numpy as np - -from qibo import set_backend -from qibo.backends import NumpyBackend -from qibo.quantum_info import random_statevector +def schmidt_decomposition( + state, partition: Union[List[int], Tuple[int, ...]], backend=None +): + backend = _check_backend(backend) -set_backend("numpy") -backend = NumpyBackend() + nqubits = backend.np.log2(state.shape[-1]) + if not nqubits.is_integer(): + raise_error(ValueError, f"dimensions of ``state`` must be a power of 2.") -# %% -nqubits = 2 -dims = 2**nqubits + nqubits = int(nqubits) + partition_2 = set(list(range(nqubits))) ^ set(partition) -new_dims = int(np.sqrt(dims)) + tensor = backend.np.reshape(state, [2] * nqubits) + tensor = backend.np.transpose(tensor, partition + partition_2) + tensor = backend.np.reshape(tensor, 2 ** len(partition), -1) -state = random_statevector(dims, backend=backend) + U, S, Vh = np.linalg.svd(tensor) -# %% -new_state = state.reshape(-1, new_dims) -U, S, V = np.linalg.svd(new_state) + return U, S, Vh diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index 3d97f1f63a..0afb802d5c 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -7,6 +7,7 @@ commutator, matrix_power, partial_trace, + schmidt_decomposition, ) from qibo.quantum_info.metrics import purity from qibo.quantum_info.random_ensembles import random_density_matrix, random_statevector @@ -130,3 +131,17 @@ def test_matrix_power(backend, power): float(backend.np.real(backend.np.trace(power))), purity(state, backend=backend), ) + + +def test_schmidt_decomposition(backend): + state_A = random_statevector(4, seed=10, backend=backend) + state_B = random_statevector(4, seed=11, backend=backend) + state = backend.np.kron(state_A, state_B) + + U, S, Vh = schmidt_decomposition(state, [0, 1], backend=backend) + + coeffs = backend.np.abs(S) ** 2 + entropy = backend.np.where(np.abs(S) < 1e-10, 0.0, backend.np.log(coeffs)) + entropy = -backend.np.sum(coeffs * entropy) + + backend.assert_allclose(entropy, 0.0) From 3469c9c540a6f4341e8413b0fa1b732b36b0ed10 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 09:15:09 +0400 Subject: [PATCH 04/16] point to svd --- src/qibo/quantum_info/linalg_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 488fecfc0e..2435b6d4d2 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -232,6 +232,6 @@ def schmidt_decomposition( tensor = backend.np.transpose(tensor, partition + partition_2) tensor = backend.np.reshape(tensor, 2 ** len(partition), -1) - U, S, Vh = np.linalg.svd(tensor) + U, S, Vh = singular_value_decomposition(tensor, backend=backend) return U, S, Vh From 248b9089b24461565aadbe0e0fedf96c99c69642 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 05:25:25 +0000 Subject: [PATCH 05/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/linalg_operations.py | 2 +- tests/test_quantum_info_operations.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 0b83d2df78..c8ac5c65a9 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -241,7 +241,7 @@ def singular_value_decomposition(matrix, backend=None): return backend.calculate_singular_value_decomposition(matrix) - + def schmidt_decomposition( state, partition: Union[List[int], Tuple[int, ...]], backend=None diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index fcf49153b5..6a80965150 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -164,6 +164,7 @@ def test_singular_value_decomposition(backend): backend.assert_allclose(S_sorted, coeffs_sorted) + def test_schmidt_decomposition(backend): state_A = random_statevector(4, seed=10, backend=backend) state_B = random_statevector(4, seed=11, backend=backend) @@ -175,4 +176,4 @@ def test_schmidt_decomposition(backend): entropy = backend.np.where(np.abs(S) < 1e-10, 0.0, backend.np.log(coeffs)) entropy = -backend.np.sum(coeffs * entropy) - backend.assert_allclose(entropy, 0.0) \ No newline at end of file + backend.assert_allclose(entropy, 0.0) From 0248926d4836559511e599a2ab373d1e4f5f07a6 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 09:36:17 +0400 Subject: [PATCH 06/16] stash --- src/qibo/quantum_info/linalg_operations.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index c8ac5c65a9..0b4961bc0a 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -242,19 +242,28 @@ def singular_value_decomposition(matrix, backend=None): return backend.calculate_singular_value_decomposition(matrix) - def schmidt_decomposition( - +def schmidt_decomposition( state, partition: Union[List[int], Tuple[int, ...]], backend=None - ): + """Return the Schmidt decomposition of a :math:`n`-qubit bipartite pure quantum ``state``. + + .. math:: + \\ket{\\psi} = \\sum_{k} \\, c_{k} \\, \\ket{\\phi_{k}}\\!\\ket{\\psi_{k}} + + Args: + state (_type_): _description_ + partition (Union[List[int], Tuple[int, ...]]): _description_ + backend (_type_, optional): _description_. Defaults to None. + + Returns: + _type_: _description_ + """ backend = _check_backend(backend) nqubits = backend.np.log2(state.shape[-1]) if not nqubits.is_integer(): raise_error(ValueError, f"dimensions of ``state`` must be a power of 2.") - - nqubits = int(nqubits) partition_2 = set(list(range(nqubits))) ^ set(partition) @@ -262,6 +271,4 @@ def schmidt_decomposition( tensor = backend.np.transpose(tensor, partition + partition_2) tensor = backend.np.reshape(tensor, 2 ** len(partition), -1) - - return singular_value_decomposition(tensor, backend=backend) From 8be4f15b985ffa50af49bfa3bfaad45be67fe403 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 09:36:22 +0400 Subject: [PATCH 07/16] api ref --- 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 e21f0cc19f..93cd0e66ec 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1975,6 +1975,12 @@ Matrix power .. autofunction:: qibo.quantum_info.matrix_power +Schmidt decomposition +""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.schmidt_decomposition + + Quantum Networks ^^^^^^^^^^^^^^^^ From c924ad0adad2e8433b8df3f30659c12dee694afb Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 09:59:13 +0400 Subject: [PATCH 08/16] docstring --- src/qibo/quantum_info/linalg_operations.py | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 0b4961bc0a..0f386d49cf 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -247,16 +247,32 @@ def schmidt_decomposition( ): """Return the Schmidt decomposition of a :math:`n`-qubit bipartite pure quantum ``state``. + Given a bipartite pure state :math:`\\ket{\\psi}\\in\\mathcal{H}_{A}\\otimes\\mathcal{H}_{B}`, + its Schmidt decomposition is given by + .. math:: - \\ket{\\psi} = \\sum_{k} \\, c_{k} \\, \\ket{\\phi_{k}}\\!\\ket{\\psi_{k}} + \\ket{\\psi} = \\sum_{k = 1}^{\\min\\{a, \\, b\\}} \\, c_{k} \\, + \\ket{\\phi_{k}} \\otimes \\ket{\\nu_{k}} \\, , + + with :math:`a` and :math:`b` being the respective cardinalities of :math:`\\mathcal{H}_{A}` + and :math:`\\mathcal{H}_{B}`, and :math:`\\{\\phi_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} + \\subset \\mathcal{H}_{A}` and :math:`\\{\\nu_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} + \\subset \\mathcal{H}_{B}` being orthonormal sets. The coefficients + :math:`\\{c_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]}` are real, non-negative, and unique + up to re-ordering. + + Args: - state (_type_): _description_ - partition (Union[List[int], Tuple[int, ...]]): _description_ - backend (_type_, optional): _description_. Defaults to None. + state (ndarray): stevector or density matrix. + partition (Union[List[int], Tuple[int, ...]]): indices of qubits in one of the two + partitions. The other partition is inferred as the remaining qubits. + 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: - _type_: _description_ + ndarray, ndarray, ndarray: """ backend = _check_backend(backend) From 9ae4dafd3b875169968d7fc7059ab042dd01ad61 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 06:01:17 +0000 Subject: [PATCH 09/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/linalg_operations.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 0f386d49cf..2c26a2f857 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -251,17 +251,17 @@ def schmidt_decomposition( its Schmidt decomposition is given by .. math:: - \\ket{\\psi} = \\sum_{k = 1}^{\\min\\{a, \\, b\\}} \\, c_{k} \\, + \\ket{\\psi} = \\sum_{k = 1}^{\\min\\{a, \\, b\\}} \\, c_{k} \\, \\ket{\\phi_{k}} \\otimes \\ket{\\nu_{k}} \\, , - + with :math:`a` and :math:`b` being the respective cardinalities of :math:`\\mathcal{H}_{A}` - and :math:`\\mathcal{H}_{B}`, and :math:`\\{\\phi_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} - \\subset \\mathcal{H}_{A}` and :math:`\\{\\nu_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} - \\subset \\mathcal{H}_{B}` being orthonormal sets. The coefficients + and :math:`\\mathcal{H}_{B}`, and :math:`\\{\\phi_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} + \\subset \\mathcal{H}_{A}` and :math:`\\{\\nu_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]} + \\subset \\mathcal{H}_{B}` being orthonormal sets. The coefficients :math:`\\{c_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]}` are real, non-negative, and unique up to re-ordering. - + Args: state (ndarray): stevector or density matrix. @@ -272,7 +272,7 @@ def schmidt_decomposition( :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. Returns: - ndarray, ndarray, ndarray: + ndarray, ndarray, ndarray: """ backend = _check_backend(backend) From b93529c98b7655013d65acd9f56a4bf007732d2b Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 10:31:36 +0400 Subject: [PATCH 10/16] comprehensive testing --- tests/test_quantum_info_operations.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index 6a80965150..60e32e516b 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -172,8 +172,20 @@ def test_schmidt_decomposition(backend): U, S, Vh = schmidt_decomposition(state, [0, 1], backend=backend) + # recovering original state + recovered = np.zeros_like(state.shape, dtype=complex) + recovered = backend.cast(recovered, dtype=recovered.dtype) + for coeff, u, vh in zip(S, U.T, Vh): + if abs(coeff) > 1e-10: + recovered = recovered + coeff * backend.np.kron(u, vh) + + print(S) + + backend.assert_allclose(recovered, state) + + # entropy test coeffs = backend.np.abs(S) ** 2 - entropy = backend.np.where(np.abs(S) < 1e-10, 0.0, backend.np.log(coeffs)) + entropy = backend.np.where(backend.np.abs(S) < 1e-10, 0.0, backend.np.log(coeffs)) entropy = -backend.np.sum(coeffs * entropy) - backend.assert_allclose(entropy, 0.0) + backend.assert_allclose(entropy, 0.0, atol=1e-14) From 7c18032f43e7f2ecd337ff1f6199bd99dc18740a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 10:37:56 +0400 Subject: [PATCH 11/16] fix bug + docstring --- src/qibo/quantum_info/linalg_operations.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 2c26a2f857..5bc1000886 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -261,7 +261,15 @@ def schmidt_decomposition( :math:`\\{c_{k}\\}_{k\\in[\\min\\{a, \\, b\\}]}` are real, non-negative, and unique up to re-ordering. + The decomposition is calculated using :func:`qibo.quantum_info.singular_value_decomposition`, + resulting in + .. math:: + \\ketbra{\\psi}{\\psi} = U \\, S \\, V^{\\dagger} \\, , + + where :math:`U` is an :math:`a \\times a` unitary matrix, :math:`V` is an :math:`b \\times b` + unitary matrix, and :math:`S` is an :math:`a \\times b` positive semidefinite diagonal matrix + that contains the singular values of :math:`\\ketbra{\\psi}{\\psi}`. Args: state (ndarray): stevector or density matrix. @@ -272,19 +280,23 @@ def schmidt_decomposition( :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. Returns: - ndarray, ndarray, ndarray: + ndarray, ndarray, ndarray: Respectively, the matrices :math:`U`, :math:`S`, + and :math:`V^{\\dagger}`. """ backend = _check_backend(backend) - nqubits = backend.np.log2(state.shape[-1]) + nqubits = math.log2(state.shape[-1]) if not nqubits.is_integer(): raise_error(ValueError, f"dimensions of ``state`` must be a power of 2.") nqubits = int(nqubits) partition_2 = set(list(range(nqubits))) ^ set(partition) + partition_2 = ( + list(partition_2) if isinstance(partition, list) else tuple(partition_2) + ) tensor = backend.np.reshape(state, [2] * nqubits) tensor = backend.np.transpose(tensor, partition + partition_2) - tensor = backend.np.reshape(tensor, 2 ** len(partition), -1) + tensor = backend.np.reshape(tensor, (2 ** len(partition), -1)) return singular_value_decomposition(tensor, backend=backend) From 142dbdc36ca7393d45530fc9d47cca189b1aa6c2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 06:38:32 +0000 Subject: [PATCH 12/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/linalg_operations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 5bc1000886..97e6662c47 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -266,7 +266,7 @@ def schmidt_decomposition( .. math:: \\ketbra{\\psi}{\\psi} = U \\, S \\, V^{\\dagger} \\, , - + where :math:`U` is an :math:`a \\times a` unitary matrix, :math:`V` is an :math:`b \\times b` unitary matrix, and :math:`S` is an :math:`a \\times b` positive semidefinite diagonal matrix that contains the singular values of :math:`\\ketbra{\\psi}{\\psi}`. @@ -280,7 +280,7 @@ def schmidt_decomposition( :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. Returns: - ndarray, ndarray, ndarray: Respectively, the matrices :math:`U`, :math:`S`, + ndarray, ndarray, ndarray: Respectively, the matrices :math:`U`, :math:`S`, and :math:`V^{\\dagger}`. """ backend = _check_backend(backend) From d67fb06995281b8dd474108e127562f91321551b Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 13:34:12 +0400 Subject: [PATCH 13/16] coverage --- tests/test_quantum_info_operations.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index 60e32e516b..aeb7220844 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -166,6 +166,10 @@ def test_singular_value_decomposition(backend): def test_schmidt_decomposition(backend): + with pytest.raises(ValueError): + test = random_statevector(3, backend=backend) + test = schmidt_decomposition(test, backend=backend) + state_A = random_statevector(4, seed=10, backend=backend) state_B = random_statevector(4, seed=11, backend=backend) state = backend.np.kron(state_A, state_B) @@ -179,8 +183,6 @@ def test_schmidt_decomposition(backend): if abs(coeff) > 1e-10: recovered = recovered + coeff * backend.np.kron(u, vh) - print(S) - backend.assert_allclose(recovered, state) # entropy test From 51123a044afc4592835005d4789cbeccc7524c66 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 13:44:11 +0400 Subject: [PATCH 14/16] replace transpiler function --- src/qibo/transpiler/unitary_decompositions.py | 31 +++---------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/src/qibo/transpiler/unitary_decompositions.py b/src/qibo/transpiler/unitary_decompositions.py index ad892db734..2de58f2ab7 100644 --- a/src/qibo/transpiler/unitary_decompositions.py +++ b/src/qibo/transpiler/unitary_decompositions.py @@ -3,6 +3,7 @@ from qibo import gates, matrices from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error +from qibo.quantum_info.linalg_operations import schmidt_decomposition magic_basis = np.array( [[1, -1j, 0, 0], [0, 0, 1, -1j], [0, 0, -1, -1j], [1, 1j, 0, 0]] @@ -84,30 +85,6 @@ def calculate_psi(unitary, magic_basis=magic_basis, backend=None): return psi, eigvals -def schmidt_decompose(state, backend=None): - """Decomposes a two-qubit product state to its single-qubit parts. - - Args: - state (ndarray): product state to be decomposed. - - Returns: - (ndarray, ndarray): decomposition - - """ - backend = _check_backend(backend) - # tf.linalg.svd has a different behaviour - if backend.__class__.__name__ == "TensorflowBackend": - u, d, v = np.linalg.svd(backend.np.reshape(state, (2, 2))) - else: - u, d, v = backend.np.linalg.svd(backend.np.reshape(state, (2, 2))) - if not np.allclose(backend.to_numpy(d), [1, 0]): # pragma: no cover - raise_error( - ValueError, - f"Unexpected singular values: {d}\nCan only decompose product states.", - ) - return u[:, 0], v[0] - - def calculate_single_qubit_unitaries(psi, backend=None): """Calculates local unitaries that maps a maximally entangled basis to the magic basis. @@ -133,8 +110,10 @@ def calculate_single_qubit_unitaries(psi, backend=None): # find e and f by inverting (A3), (A4) ef = (psi_bar[0] + 1j * psi_bar[1]) / np.sqrt(2) e_f_ = (psi_bar[0] - 1j * psi_bar[1]) / np.sqrt(2) - e, f = schmidt_decompose(ef, backend=backend) - e_, f_ = schmidt_decompose(e_f_, backend=backend) + e, _, f = schmidt_decomposition(ef, [0], backend=backend) + e, f = e[:, 0], f[0] + e_, _, f_ = schmidt_decomposition(e_f_, [0], backend=backend) + e_, f_ = e_[:, 0], f_[0] # find exp(1j * delta) using (A5a) ef_ = backend.np.kron(e, f_) phase = ( From 8474a15ec52eaaec54fdd1b1accd03fb7becd178 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 7 Oct 2024 14:09:43 +0400 Subject: [PATCH 15/16] fix test --- tests/test_quantum_info_operations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quantum_info_operations.py b/tests/test_quantum_info_operations.py index aeb7220844..4a9d3c0513 100644 --- a/tests/test_quantum_info_operations.py +++ b/tests/test_quantum_info_operations.py @@ -168,7 +168,7 @@ def test_singular_value_decomposition(backend): def test_schmidt_decomposition(backend): with pytest.raises(ValueError): test = random_statevector(3, backend=backend) - test = schmidt_decomposition(test, backend=backend) + test = schmidt_decomposition(test, [0], backend=backend) state_A = random_statevector(4, seed=10, backend=backend) state_B = random_statevector(4, seed=11, backend=backend) From dcee04a5f20fd080a140e5046beae78aa42f42b8 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 16 Oct 2024 07:00:17 +0000 Subject: [PATCH 16/16] Update src/qibo/quantum_info/linalg_operations.py Co-authored-by: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> --- src/qibo/quantum_info/linalg_operations.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index ac3674aa3e..395f93b665 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -375,10 +375,7 @@ def schmidt_decomposition( raise_error(ValueError, f"dimensions of ``state`` must be a power of 2.") nqubits = int(nqubits) - partition_2 = set(list(range(nqubits))) ^ set(partition) - partition_2 = ( - list(partition_2) if isinstance(partition, list) else tuple(partition_2) - ) + partition_2 = partition.__class__(set(list(range(nqubits))) ^ set(partition)) tensor = backend.np.reshape(state, [2] * nqubits) tensor = backend.np.transpose(tensor, partition + partition_2)