From ca95b3cb965bc2be106fc8990d49d1d3c84c7525 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Tue, 15 Oct 2024 11:53:56 +0530 Subject: [PATCH 01/23] add complementary channels --- toqito/channel_ops/complementary_channel.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 toqito/channel_ops/complementary_channel.py diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py new file mode 100644 index 000000000..ef0456938 --- /dev/null +++ b/toqito/channel_ops/complementary_channel.py @@ -0,0 +1,5 @@ +"""Computes the complementary channel/map of a superoperator.""" + +import numpy as np + +from toqito.perms import swap From caf78234568ce01c6833c8dab79ab526cd54edd7 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Thu, 17 Oct 2024 23:10:50 +0530 Subject: [PATCH 02/23] update complementary map --- toqito/channel_ops/complementary_channel.py | 92 ++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index ef0456938..e45507e76 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -2,4 +2,94 @@ import numpy as np -from toqito.perms import swap + +def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: + r"""Compute the Kraus operators for the complementary map of a quantum channel. + + (Section: Representations and Characterizations of Channels from :cite:`Watrous_2018_TQI`). + + The complementary map is derived from the given quantum channel's Kraus operators by + rearranging the rows of the input Kraus operators into the Kraus operators of the + complementary map. + + Specifically, for each Kraus operator :math:`K_i` in the input channel :math:`\Phi`, + we define the complementary Kraus operators :math:`K_i^C` by stacking the rows of + :math:`K_i` from all Kraus operators vertically. + + Examples + ========== + + Suppose the following Kraus operators define a quantum channel: + + .. math:: + K_1 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 1 & 0 \\ + 0 & 1 + \end{pmatrix}, + K_2 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 1 \\ + 1 & 0 + \end{pmatrix}, + K_3 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & -i \\ + i & 0 + \end{pmatrix}, + K_4 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 1 & 0 \\ + 0 & -1 + \end{pmatrix} + + To compute the Kraus operators for the complementary map, we rearrange the rows of these + Kraus operators as follows: + + >>> import numpy as np + >>> kraus_ops_Phi = [ + ... np.array([[1, 0], [0, 1]]) / np.sqrt(2), + ... np.array([[0, 1], [1, 0]]) / np.sqrt(2), + ... np.array([[0, -1j], [1j, 0]]) / np.sqrt(2), + ... np.array([[1, 0], [0, -1]]) / np.sqrt(2) + ... ] + >>> comp_kraus_ops = complementary_map(kraus_ops_Phi) + >>> for i, op in enumerate(comp_kraus_ops): + ... print(f"Kraus operator {i + 1}:\n{op}\n") + + The output would be: + + .. math:: + K_1^C = \frac{1}{\sqrt{2}} \begin{pmatrix} + 1 & 0 \\ + 0 & 1 \\ + 0 & -i \\ + 1 & 0 + \end{pmatrix}, + K_2^C = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 1 \\ + 1 & 0 \\ + i & 0 \\ + 0 & -1 + \end{pmatrix} + + References + ========== + .. bibliography:: + :filter: docname in docnames + + :raises ValueError: If the input is not a valid list of Kraus operators. + :param kraus_ops: A list of numpy arrays representing the Kraus operators of a quantum channel. + Each Kraus operator is assumed to be a square matrix. + :return: A list of numpy arrays representing the Kraus operators of the complementary map. + + """ + num_kraus = len(kraus_ops) + op_dim = kraus_ops[0].shape[0] + + if any(k.shape[0] != k.shape[1] for k in kraus_ops): + raise ValueError("All Kraus operators must be square matrices.") + + comp_kraus_ops = [] + + for row in range(op_dim): + comp_kraus_op = np.vstack([kraus_ops[i][row, :] for i in range(num_kraus)]) + comp_kraus_ops.append(comp_kraus_op) + + return comp_kraus_ops From 6655a3453369e888f8e9d021a532e0006b2e34b3 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Thu, 17 Oct 2024 23:17:42 +0530 Subject: [PATCH 03/23] added tests and import in init --- toqito/channel_ops/__init__.py | 1 + .../tests/test_complmentary_channel.py | 99 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 toqito/channel_ops/tests/test_complmentary_channel.py diff --git a/toqito/channel_ops/__init__.py b/toqito/channel_ops/__init__.py index 3583867e0..bef29157b 100644 --- a/toqito/channel_ops/__init__.py +++ b/toqito/channel_ops/__init__.py @@ -5,3 +5,4 @@ from toqito.channel_ops.choi_to_kraus import choi_to_kraus from toqito.channel_ops.kraus_to_choi import kraus_to_choi from toqito.channel_ops.dual_channel import dual_channel +from toqito.channel_ops.complementary_channel import complementary_channel diff --git a/toqito/channel_ops/tests/test_complmentary_channel.py b/toqito/channel_ops/tests/test_complmentary_channel.py new file mode 100644 index 000000000..c5f27845b --- /dev/null +++ b/toqito/channel_ops/tests/test_complmentary_channel.py @@ -0,0 +1,99 @@ +"""Tests for complementary_map.""" + +import numpy as np +import pytest +from toqito.channel_ops import complementary_map + +# Define test cases for complementary map +kraus_1 = np.array([[1, 0], [0, 1]]) / np.sqrt(2) +kraus_2 = np.array([[0, 1], [1, 0]]) / np.sqrt(2) +kraus_3 = np.array([[0, -1j], [1j, 0]]) / np.sqrt(2) +kraus_4 = np.array([[1, 0], [0, -1]]) / np.sqrt(2) + +# Expected results for the complementary map +expected_res_comp = [ + np.array([[1, 0], [0, 1], [0, -1j], [1, 0]]) / np.sqrt(2), + np.array([[0, 1], [1, 0], [1j, 0], [0, -1]]) / np.sqrt(2), +] + +# Higher-dimensional Kraus operators (3x3) +kraus_5 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / np.sqrt(3) +kraus_6 = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3) + +expected_res_comp_high_dim = [ + np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3), + np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 0], [1, 0, 1]]) / np.sqrt(3), +] + +# Single Kraus operator (edge case) +kraus_single = np.array([[1, 0], [0, 1]]) + +expected_res_single = [np.array([[1, 0], [0, 1]])] + +# Large size (4x4 Kraus operator) +kraus_large_1 = np.eye(4) +kraus_large_2 = np.fliplr(np.eye(4)) + +expected_res_large = [ + np.vstack([np.eye(4)[i, :] for i in range(4)]), + np.vstack([np.fliplr(np.eye(4))[i, :] for i in range(4)]), +] + +@pytest.mark.parametrize( + "kraus_ops, expected", + [ + # Test complementary_map on a set of 2x2 Kraus operators (the ones you gave). + ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), + # Test complementary_map with higher-dimensional (3x3) Kraus operators. + ([kraus_5, kraus_6], expected_res_comp_high_dim), + # Test complementary_map with a single Kraus operator (edge case). + ([kraus_single], expected_res_single), + # Test complementary_map with large (4x4) Kraus operators. + ([kraus_large_1, kraus_large_2], expected_res_large), + ], +) +def test_complementary_map(kraus_ops, expected): + """Test complementary_map works as expected for valid inputs.""" + calculated = complementary_map(kraus_ops) + for calc_op, exp_op in zip(calculated, expected): + assert np.isclose(calc_op, exp_op).all() + +@pytest.mark.parametrize( + "kraus_ops", + [ + # Invalid test case: non-square matrices + ([np.array([[1, 0, 0], [0, 1, 0]])]), # Not a square matrix + # Invalid test case: empty list of Kraus operators + ([]), + # Invalid test case: single row matrix (not a square) + ([np.array([[1, 0]])]), + ], +) +def test_complementary_map_error(kraus_ops): + """Test function raises error as expected for invalid inputs.""" + with pytest.raises(ValueError): + complementary_map(kraus_ops) + +@pytest.mark.parametrize( + "kraus_ops", + [ + # Test complementary_map with identity operator (should return same operator rows stacked). + ([np.eye(2)]), + # Test complementary_map with Kraus operators that are zero matrices. + ([np.zeros((2, 2))]), + ], +) +def test_complementary_map_special_cases(kraus_ops): + """Test complementary_map handles special cases like identity or zero operators.""" + # Calculate the complementary map + calculated = complementary_map(kraus_ops) + + # For identity, the complementary map should stack identity rows + if np.array_equal(kraus_ops[0], np.eye(2)): + expected = [np.eye(2)] + assert np.isclose(calculated, expected).all() + + # For zero operators, complementary map should be zero as well + if np.array_equal(kraus_ops[0], np.zeros((2, 2))): + expected = [np.zeros((2, 2))] + assert np.isclose(calculated, expected).all() From 3d6f1ee4c58a5a9c04043d4bbfdb9c7dfde5907e Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Thu, 17 Oct 2024 23:43:57 +0530 Subject: [PATCH 04/23] ruff check applied --- toqito/channel_ops/tests/test_complmentary_channel.py | 1 + 1 file changed, 1 insertion(+) diff --git a/toqito/channel_ops/tests/test_complmentary_channel.py b/toqito/channel_ops/tests/test_complmentary_channel.py index c5f27845b..54c02093c 100644 --- a/toqito/channel_ops/tests/test_complmentary_channel.py +++ b/toqito/channel_ops/tests/test_complmentary_channel.py @@ -2,6 +2,7 @@ import numpy as np import pytest + from toqito.channel_ops import complementary_map # Define test cases for complementary map From 5b06b6a5c08b58a2e601fc88a2e970ccfac09aaf Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Thu, 17 Oct 2024 23:48:13 +0530 Subject: [PATCH 05/23] update test file --- .../tests/test_complmentary_channel.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/toqito/channel_ops/tests/test_complmentary_channel.py b/toqito/channel_ops/tests/test_complmentary_channel.py index 54c02093c..d88499504 100644 --- a/toqito/channel_ops/tests/test_complmentary_channel.py +++ b/toqito/channel_ops/tests/test_complmentary_channel.py @@ -1,9 +1,9 @@ -"""Tests for complementary_map.""" +"""Tests for complementary_channel.""" import numpy as np import pytest -from toqito.channel_ops import complementary_map +from toqito.channel_ops import complementary_channel # Define test cases for complementary map kraus_1 = np.array([[1, 0], [0, 1]]) / np.sqrt(2) @@ -43,19 +43,19 @@ @pytest.mark.parametrize( "kraus_ops, expected", [ - # Test complementary_map on a set of 2x2 Kraus operators (the ones you gave). + # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), - # Test complementary_map with higher-dimensional (3x3) Kraus operators. + # Test complementary_channel with higher-dimensional (3x3) Kraus operators. ([kraus_5, kraus_6], expected_res_comp_high_dim), - # Test complementary_map with a single Kraus operator (edge case). + # Test complementary_channel with a single Kraus operator (edge case). ([kraus_single], expected_res_single), - # Test complementary_map with large (4x4) Kraus operators. + # Test complementary_channel with large (4x4) Kraus operators. ([kraus_large_1, kraus_large_2], expected_res_large), ], ) -def test_complementary_map(kraus_ops, expected): - """Test complementary_map works as expected for valid inputs.""" - calculated = complementary_map(kraus_ops) +def test_complementary_channel(kraus_ops, expected): + """Test complementary_channel works as expected for valid inputs.""" + calculated = complementary_channel(kraus_ops) for calc_op, exp_op in zip(calculated, expected): assert np.isclose(calc_op, exp_op).all() @@ -70,24 +70,24 @@ def test_complementary_map(kraus_ops, expected): ([np.array([[1, 0]])]), ], ) -def test_complementary_map_error(kraus_ops): +def test_complementary_channel_error(kraus_ops): """Test function raises error as expected for invalid inputs.""" with pytest.raises(ValueError): - complementary_map(kraus_ops) + complementary_channel(kraus_ops) @pytest.mark.parametrize( "kraus_ops", [ - # Test complementary_map with identity operator (should return same operator rows stacked). + # Test complementary_channel with identity operator (should return same operator rows stacked). ([np.eye(2)]), - # Test complementary_map with Kraus operators that are zero matrices. + # Test complementary_channel with Kraus operators that are zero matrices. ([np.zeros((2, 2))]), ], ) -def test_complementary_map_special_cases(kraus_ops): - """Test complementary_map handles special cases like identity or zero operators.""" +def test_complementary_channel_special_cases(kraus_ops): + """Test complementary_channel handles special cases like identity or zero operators.""" # Calculate the complementary map - calculated = complementary_map(kraus_ops) + calculated = complementary_channel(kraus_ops) # For identity, the complementary map should stack identity rows if np.array_equal(kraus_ops[0], np.eye(2)): From 398b282431cff6f7939b82c914ceb45c451f7daa Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Thu, 17 Oct 2024 23:54:28 +0530 Subject: [PATCH 06/23] update map to channel --- toqito/channel_ops/complementary_channel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index e45507e76..6031af8f1 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -49,7 +49,7 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: ... np.array([[0, -1j], [1j, 0]]) / np.sqrt(2), ... np.array([[1, 0], [0, -1]]) / np.sqrt(2) ... ] - >>> comp_kraus_ops = complementary_map(kraus_ops_Phi) + >>> comp_kraus_ops = complementary_channel(kraus_ops_Phi) >>> for i, op in enumerate(comp_kraus_ops): ... print(f"Kraus operator {i + 1}:\n{op}\n") From b51a6985431825e5dcee1ddcc7d882bb8aabb54d Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Fri, 18 Oct 2024 00:02:43 +0530 Subject: [PATCH 07/23] remove doc example for now --- toqito/channel_ops/complementary_channel.py | 29 --------------------- 1 file changed, 29 deletions(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 6031af8f1..5ea156616 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -39,35 +39,6 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: 0 & -1 \end{pmatrix} - To compute the Kraus operators for the complementary map, we rearrange the rows of these - Kraus operators as follows: - - >>> import numpy as np - >>> kraus_ops_Phi = [ - ... np.array([[1, 0], [0, 1]]) / np.sqrt(2), - ... np.array([[0, 1], [1, 0]]) / np.sqrt(2), - ... np.array([[0, -1j], [1j, 0]]) / np.sqrt(2), - ... np.array([[1, 0], [0, -1]]) / np.sqrt(2) - ... ] - >>> comp_kraus_ops = complementary_channel(kraus_ops_Phi) - >>> for i, op in enumerate(comp_kraus_ops): - ... print(f"Kraus operator {i + 1}:\n{op}\n") - - The output would be: - - .. math:: - K_1^C = \frac{1}{\sqrt{2}} \begin{pmatrix} - 1 & 0 \\ - 0 & 1 \\ - 0 & -i \\ - 1 & 0 - \end{pmatrix}, - K_2^C = \frac{1}{\sqrt{2}} \begin{pmatrix} - 0 & 1 \\ - 1 & 0 \\ - i & 0 \\ - 0 & -1 - \end{pmatrix} References ========== From 303bfe6ec877292f2f7fce5258c6a0e8eb04a13d Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Fri, 18 Oct 2024 00:50:12 +0530 Subject: [PATCH 08/23] updated test complmentary_channel --- .../channel_ops/tests/test_complmentary_channel.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/toqito/channel_ops/tests/test_complmentary_channel.py b/toqito/channel_ops/tests/test_complmentary_channel.py index d88499504..052027082 100644 --- a/toqito/channel_ops/tests/test_complmentary_channel.py +++ b/toqito/channel_ops/tests/test_complmentary_channel.py @@ -13,8 +13,8 @@ # Expected results for the complementary map expected_res_comp = [ - np.array([[1, 0], [0, 1], [0, -1j], [1, 0]]) / np.sqrt(2), - np.array([[0, 1], [1, 0], [1j, 0], [0, -1]]) / np.sqrt(2), + np.array([[1, 0], [0, 1], [0, 0], [0, -1j]]), + np.array([[0, 1], [1, 0], [1j, 0], [0, -1]]), ] # Higher-dimensional Kraus operators (3x3) @@ -22,14 +22,14 @@ kraus_6 = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3) expected_res_comp_high_dim = [ - np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3), - np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 0], [1, 0, 1]]) / np.sqrt(3), + np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0]]), + np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 0, 0]]), ] # Single Kraus operator (edge case) kraus_single = np.array([[1, 0], [0, 1]]) -expected_res_single = [np.array([[1, 0], [0, 1]])] +expected_res_single = [np.array([[1, 0], [0, 1]])] # Same as input # Large size (4x4 Kraus operator) kraus_large_1 = np.eye(4) @@ -92,9 +92,9 @@ def test_complementary_channel_special_cases(kraus_ops): # For identity, the complementary map should stack identity rows if np.array_equal(kraus_ops[0], np.eye(2)): expected = [np.eye(2)] - assert np.isclose(calculated, expected).all() + assert np.isclose(calculated[0], expected[0]).all() # For zero operators, complementary map should be zero as well if np.array_equal(kraus_ops[0], np.zeros((2, 2))): expected = [np.zeros((2, 2))] - assert np.isclose(calculated, expected).all() + assert np.isclose(calculated[0], expected[0]).all() From 59108434eab47c71fc3f05be119450240ec38e40 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Fri, 18 Oct 2024 11:06:15 +0530 Subject: [PATCH 09/23] update test file name --- ...test_complmentary_channel.py => test_complementary_channel.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename toqito/channel_ops/tests/{test_complmentary_channel.py => test_complementary_channel.py} (100%) diff --git a/toqito/channel_ops/tests/test_complmentary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py similarity index 100% rename from toqito/channel_ops/tests/test_complmentary_channel.py rename to toqito/channel_ops/tests/test_complementary_channel.py From 49dde29f20bceba1b4e62bce3baf4eb21f6cccdc Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Fri, 18 Oct 2024 11:37:11 +0530 Subject: [PATCH 10/23] asserting shape mismatches --- toqito/channel_ops/tests/test_complementary_channel.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index 052027082..b28e6469e 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -56,8 +56,11 @@ def test_complementary_channel(kraus_ops, expected): """Test complementary_channel works as expected for valid inputs.""" calculated = complementary_channel(kraus_ops) + + # Compare the shapes first to debug broadcasting issues + assert len(calculated) == len(expected), "Mismatch in number of Kraus operators" for calc_op, exp_op in zip(calculated, expected): - assert np.isclose(calc_op, exp_op).all() + assert np.isclose(calc_op, exp_op, atol=1e-6).all() @pytest.mark.parametrize( "kraus_ops", From 38416c71c1eacbd44da773e7348db252096c01e4 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 19 Oct 2024 15:23:10 +0530 Subject: [PATCH 11/23] update complementary channel --- toqito/channel_ops/complementary_channel.py | 24 ----------- .../tests/test_complementary_channel.py | 42 +++++++++---------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 5ea156616..1b2211c2e 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -16,30 +16,6 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: we define the complementary Kraus operators :math:`K_i^C` by stacking the rows of :math:`K_i` from all Kraus operators vertically. - Examples - ========== - - Suppose the following Kraus operators define a quantum channel: - - .. math:: - K_1 = \frac{1}{\sqrt{2}} \begin{pmatrix} - 1 & 0 \\ - 0 & 1 - \end{pmatrix}, - K_2 = \frac{1}{\sqrt{2}} \begin{pmatrix} - 0 & 1 \\ - 1 & 0 - \end{pmatrix}, - K_3 = \frac{1}{\sqrt{2}} \begin{pmatrix} - 0 & -i \\ - i & 0 - \end{pmatrix}, - K_4 = \frac{1}{\sqrt{2}} \begin{pmatrix} - 1 & 0 \\ - 0 & -1 - \end{pmatrix} - - References ========== .. bibliography:: diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index b28e6469e..1d87a69a5 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -40,27 +40,27 @@ np.vstack([np.fliplr(np.eye(4))[i, :] for i in range(4)]), ] -@pytest.mark.parametrize( - "kraus_ops, expected", - [ - # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). - ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), - # Test complementary_channel with higher-dimensional (3x3) Kraus operators. - ([kraus_5, kraus_6], expected_res_comp_high_dim), - # Test complementary_channel with a single Kraus operator (edge case). - ([kraus_single], expected_res_single), - # Test complementary_channel with large (4x4) Kraus operators. - ([kraus_large_1, kraus_large_2], expected_res_large), - ], -) -def test_complementary_channel(kraus_ops, expected): - """Test complementary_channel works as expected for valid inputs.""" - calculated = complementary_channel(kraus_ops) - - # Compare the shapes first to debug broadcasting issues - assert len(calculated) == len(expected), "Mismatch in number of Kraus operators" - for calc_op, exp_op in zip(calculated, expected): - assert np.isclose(calc_op, exp_op, atol=1e-6).all() +# @pytest.mark.parametrize( +# "kraus_ops, expected", +# [ +# # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). +# ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), +# # Test complementary_channel with higher-dimensional (3x3) Kraus operators. +# ([kraus_5, kraus_6], expected_res_comp_high_dim), +# # Test complementary_channel with a single Kraus operator (edge case). +# ([kraus_single], expected_res_single), +# # Test complementary_channel with large (4x4) Kraus operators. +# ([kraus_large_1, kraus_large_2], expected_res_large), +# ], +# ) +# def test_complementary_channel(kraus_ops, expected): +# """Test complementary_channel works as expected for valid inputs.""" +# calculated = complementary_channel(kraus_ops) + +# # Compare the shapes first to debug broadcasting issues +# assert len(calculated) == len(expected), "Mismatch in number of Kraus operators" +# for calc_op, exp_op in zip(calculated, expected): +# assert np.isclose(calc_op, exp_op, atol=1e-6).all() @pytest.mark.parametrize( "kraus_ops", From a7c8eb1adc4cd8ea39cce343d9e872b3af77506b Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 19 Oct 2024 15:48:31 +0530 Subject: [PATCH 12/23] removing tests for now --- .../tests/test_complementary_channel.py | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index 1d87a69a5..53effef27 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -62,42 +62,42 @@ # for calc_op, exp_op in zip(calculated, expected): # assert np.isclose(calc_op, exp_op, atol=1e-6).all() -@pytest.mark.parametrize( - "kraus_ops", - [ - # Invalid test case: non-square matrices - ([np.array([[1, 0, 0], [0, 1, 0]])]), # Not a square matrix - # Invalid test case: empty list of Kraus operators - ([]), - # Invalid test case: single row matrix (not a square) - ([np.array([[1, 0]])]), - ], -) -def test_complementary_channel_error(kraus_ops): - """Test function raises error as expected for invalid inputs.""" - with pytest.raises(ValueError): - complementary_channel(kraus_ops) - -@pytest.mark.parametrize( - "kraus_ops", - [ - # Test complementary_channel with identity operator (should return same operator rows stacked). - ([np.eye(2)]), - # Test complementary_channel with Kraus operators that are zero matrices. - ([np.zeros((2, 2))]), - ], -) -def test_complementary_channel_special_cases(kraus_ops): - """Test complementary_channel handles special cases like identity or zero operators.""" - # Calculate the complementary map - calculated = complementary_channel(kraus_ops) - - # For identity, the complementary map should stack identity rows - if np.array_equal(kraus_ops[0], np.eye(2)): - expected = [np.eye(2)] - assert np.isclose(calculated[0], expected[0]).all() - - # For zero operators, complementary map should be zero as well - if np.array_equal(kraus_ops[0], np.zeros((2, 2))): - expected = [np.zeros((2, 2))] - assert np.isclose(calculated[0], expected[0]).all() +# @pytest.mark.parametrize( +# "kraus_ops", +# [ +# # Invalid test case: non-square matrices +# ([np.array([[1, 0, 0], [0, 1, 0]])]), # Not a square matrix +# # Invalid test case: empty list of Kraus operators +# ([]), +# # Invalid test case: single row matrix (not a square) +# ([np.array([[1, 0]])]), +# ], +# ) +# def test_complementary_channel_error(kraus_ops): +# """Test function raises error as expected for invalid inputs.""" +# with pytest.raises(ValueError): +# complementary_channel(kraus_ops) + +# @pytest.mark.parametrize( +# "kraus_ops", +# [ +# # Test complementary_channel with identity operator (should return same operator rows stacked). +# ([np.eye(2)]), +# # Test complementary_channel with Kraus operators that are zero matrices. +# ([np.zeros((2, 2))]), +# ], +# ) +# def test_complementary_channel_special_cases(kraus_ops): +# """Test complementary_channel handles special cases like identity or zero operators.""" +# # Calculate the complementary map +# calculated = complementary_channel(kraus_ops) + +# # For identity, the complementary map should stack identity rows +# if np.array_equal(kraus_ops[0], np.eye(2)): +# expected = [np.eye(2)] +# assert np.isclose(calculated[0], expected[0]).all() + +# # For zero operators, complementary map should be zero as well +# if np.array_equal(kraus_ops[0], np.zeros((2, 2))): +# expected = [np.zeros((2, 2))] +# assert np.isclose(calculated[0], expected[0]).all() From a866e61abc542aea62f9a5cf6752dcbb6ffd7af9 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 19 Oct 2024 16:58:00 +0530 Subject: [PATCH 13/23] update tests --- .../tests/test_complementary_channel.py | 69 +++++++++---------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index 53effef27..be21d4746 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -6,15 +6,15 @@ from toqito.channel_ops import complementary_channel # Define test cases for complementary map -kraus_1 = np.array([[1, 0], [0, 1]]) / np.sqrt(2) -kraus_2 = np.array([[0, 1], [1, 0]]) / np.sqrt(2) -kraus_3 = np.array([[0, -1j], [1j, 0]]) / np.sqrt(2) -kraus_4 = np.array([[1, 0], [0, -1]]) / np.sqrt(2) +kraus_1 = np.array([[1, 0], [0, 0]]) +kraus_2 = np.array([[0, 1], [0, 0]]) +kraus_3 = np.array([[0, 0], [1, 0]]) +kraus_4 = np.array([[0, 0], [0, 1]]) # Expected results for the complementary map expected_res_comp = [ - np.array([[1, 0], [0, 1], [0, 0], [0, -1j]]), - np.array([[0, 1], [1, 0], [1j, 0], [0, -1]]), + np.array([[1, 0], [0, 1], [0, 0], [0, 0]]), + np.array([[0, 0], [0, 0], [1, 0], [0, 1]]), ] # Higher-dimensional Kraus operators (3x3) @@ -22,45 +22,38 @@ kraus_6 = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3) expected_res_comp_high_dim = [ - np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0]]), - np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 0, 0]]), + np.array([[1, 0, 0], [0, 1, 0]]) / np.sqrt(3), + np.array([[0, 1, 0], [1, 0, 1]]) / np.sqrt(3), + np.array([[0, 0, 1], [0, 1, 0]]) / np.sqrt(3), ] # Single Kraus operator (edge case) kraus_single = np.array([[1, 0], [0, 1]]) -expected_res_single = [np.array([[1, 0], [0, 1]])] # Same as input - -# Large size (4x4 Kraus operator) -kraus_large_1 = np.eye(4) -kraus_large_2 = np.fliplr(np.eye(4)) - -expected_res_large = [ - np.vstack([np.eye(4)[i, :] for i in range(4)]), - np.vstack([np.fliplr(np.eye(4))[i, :] for i in range(4)]), +expected_res_single =[ + np.array([[1, 0]]), + np.array([[0, 1]]), ] -# @pytest.mark.parametrize( -# "kraus_ops, expected", -# [ -# # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). -# ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), -# # Test complementary_channel with higher-dimensional (3x3) Kraus operators. -# ([kraus_5, kraus_6], expected_res_comp_high_dim), -# # Test complementary_channel with a single Kraus operator (edge case). -# ([kraus_single], expected_res_single), -# # Test complementary_channel with large (4x4) Kraus operators. -# ([kraus_large_1, kraus_large_2], expected_res_large), -# ], -# ) -# def test_complementary_channel(kraus_ops, expected): -# """Test complementary_channel works as expected for valid inputs.""" -# calculated = complementary_channel(kraus_ops) - -# # Compare the shapes first to debug broadcasting issues -# assert len(calculated) == len(expected), "Mismatch in number of Kraus operators" -# for calc_op, exp_op in zip(calculated, expected): -# assert np.isclose(calc_op, exp_op, atol=1e-6).all() +@pytest.mark.parametrize( + "kraus_ops, expected", + [ + # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). + ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), + # Test complementary_channel with higher-dimensional (3x3) Kraus operators. + ([kraus_5, kraus_6], expected_res_comp_high_dim), + # Test complementary_channel with a single Kraus operator (edge case). + ([kraus_single], expected_res_single), + ], +) +def test_complementary_channel(kraus_ops, expected): + """Test complementary_channel works as expected for valid inputs.""" + calculated = complementary_channel(kraus_ops) + + # Compare the shapes first to debug broadcasting issues + assert len(calculated) == len(expected), "Mismatch in number of Kraus operators" + for calc_op, exp_op in zip(calculated, expected): + assert np.isclose(calc_op, exp_op, atol=1e-6).all() # @pytest.mark.parametrize( # "kraus_ops", From 7139e6f8681d60d065aa9317ddc9be0e7920fe13 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 19 Oct 2024 17:08:13 +0530 Subject: [PATCH 14/23] update invalid test case included --- .../tests/test_complementary_channel.py | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index be21d4746..de97d6388 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -55,42 +55,18 @@ def test_complementary_channel(kraus_ops, expected): for calc_op, exp_op in zip(calculated, expected): assert np.isclose(calc_op, exp_op, atol=1e-6).all() -# @pytest.mark.parametrize( -# "kraus_ops", -# [ -# # Invalid test case: non-square matrices -# ([np.array([[1, 0, 0], [0, 1, 0]])]), # Not a square matrix -# # Invalid test case: empty list of Kraus operators -# ([]), -# # Invalid test case: single row matrix (not a square) -# ([np.array([[1, 0]])]), -# ], -# ) -# def test_complementary_channel_error(kraus_ops): -# """Test function raises error as expected for invalid inputs.""" -# with pytest.raises(ValueError): -# complementary_channel(kraus_ops) - -# @pytest.mark.parametrize( -# "kraus_ops", -# [ -# # Test complementary_channel with identity operator (should return same operator rows stacked). -# ([np.eye(2)]), -# # Test complementary_channel with Kraus operators that are zero matrices. -# ([np.zeros((2, 2))]), -# ], -# ) -# def test_complementary_channel_special_cases(kraus_ops): -# """Test complementary_channel handles special cases like identity or zero operators.""" -# # Calculate the complementary map -# calculated = complementary_channel(kraus_ops) - -# # For identity, the complementary map should stack identity rows -# if np.array_equal(kraus_ops[0], np.eye(2)): -# expected = [np.eye(2)] -# assert np.isclose(calculated[0], expected[0]).all() - -# # For zero operators, complementary map should be zero as well -# if np.array_equal(kraus_ops[0], np.zeros((2, 2))): -# expected = [np.zeros((2, 2))] -# assert np.isclose(calculated[0], expected[0]).all() +@pytest.mark.parametrize( + "kraus_ops", + [ + # Invalid test case: non-square matrices + ([np.array([[1, 0, 0], [0, 1, 0]])]), # Not a square matrix + # Invalid test case: empty list of Kraus operators + ([]), + # Invalid test case: single row matrix (not a square) + ([np.array([[1, 0]])]), + ], +) +def test_complementary_channel_error(kraus_ops): + """Test function raises error as expected for invalid inputs.""" + with pytest.raises(ValueError): + complementary_channel(kraus_ops) From 58def85e3f8db38ec38520f1991b5df103f6c089 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 19 Oct 2024 17:28:13 +0530 Subject: [PATCH 15/23] error handled for empty inputs --- toqito/channel_ops/complementary_channel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 1b2211c2e..89fff4bdd 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -28,6 +28,9 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: """ num_kraus = len(kraus_ops) + if num_kraus==0: + raise ValueError("All Kraus operators must be non-empty matrices.") + op_dim = kraus_ops[0].shape[0] if any(k.shape[0] != k.shape[1] for k in kraus_ops): From d5b9517dda1c712ea498666e06748fda3574c02b Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Tue, 22 Oct 2024 19:40:47 +0530 Subject: [PATCH 16/23] adding docstring example --- toqito/channel_ops/complementary_channel.py | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 89fff4bdd..7d4dbc9e1 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -16,6 +16,53 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: we define the complementary Kraus operators :math:`K_i^C` by stacking the rows of :math:`K_i` from all Kraus operators vertically. + Examples + ========== + Suppose the following Kraus operators define a quantum channel: + .. math:: + K_1 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 1 & 0 \\ + 0 & 0 + \end{pmatrix}, + K_2 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 1 \\ + 0 & 0 + \end{pmatrix}, + K_3 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 0 \\ + 1 & 0 + \end{pmatrix}, + K_4 = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 0 \\ + 0 & 1 + \end{pmatrix} + To compute the Kraus operators for the complementary map, we rearrange the rows of these + Kraus operators as follows: + >>> import numpy as np + >>> kraus_ops_Phi = [ + ... np.array([[1, 0], [0, 0]]), + ... np.array([[0, 1], [0, 0]]), + ... np.array([[0, 0], [1, 0]]), + ... np.array([[0, 0], [0, 1]]) + ... ] + >>> comp_kraus_ops = complementary_map(kraus_ops_Phi) + >>> for i, op in enumerate(comp_kraus_ops): + ... print(f"Kraus operator {i + 1}:\n{op}\n") + The output would be: + .. math:: + K_1^C = \frac{1}{\sqrt{2}} \begin{pmatrix} + 1 & 0 \\ + 0 & 1 \\ + 0 & 0 \\ + 0 & 0 + \end{pmatrix}, + K_2^C = \frac{1}{\sqrt{2}} \begin{pmatrix} + 0 & 0 \\ + 0 & 0 \\ + 1 & 0 \\ + 0 & 1 + \end{pmatrix} + References ========== .. bibliography:: From 765191a1fb3a3e073387180a8855c6f88d55427a Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 11:41:03 +0530 Subject: [PATCH 17/23] adding more kraus operator checks --- toqito/channel_ops/complementary_channel.py | 11 +++++++++-- .../channel_ops/tests/test_complementary_channel.py | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 7d4dbc9e1..c8f9a2a33 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -80,8 +80,15 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: op_dim = kraus_ops[0].shape[0] - if any(k.shape[0] != k.shape[1] for k in kraus_ops): - raise ValueError("All Kraus operators must be square matrices.") + if (any(k.shape[0] != k.shape[1] for k in kraus_ops) and any(k.shape[0] != op_dim for k in kraus_ops)): + raise ValueError("All Kraus operators must be equal size square matrices.") + + # Check the Kraus completeness relation: ∑ K_i† K_i = I + identity = np.eye(op_dim, dtype=kraus_ops[0].dtype) + sum_k_dagger_k = sum(k.T.conj() @ k for k in kraus_ops) + + if not np.allclose(sum_k_dagger_k, identity): + raise ValueError("The Kraus operators do not satisfy the completeness relation ∑ K_i† K_i = I.") comp_kraus_ops = [] diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index de97d6388..2ed78b9ad 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -64,6 +64,10 @@ def test_complementary_channel(kraus_ops, expected): ([]), # Invalid test case: single row matrix (not a square) ([np.array([[1, 0]])]), + # Different dimenisions for kraus operators in a set + ([np.array([[1, 0, 0], [0, 1, 0], [0, 1, 1]]), np.array([[1, 0], [0, 1]])]), + # Invalid test case: Kraus operators that do not satisfy the completeness relation + ([np.array([[1, 0], [0, 0.5]]), np.array([[0, 0.5], [0, 0.5]])]), # Sum != I ], ) def test_complementary_channel_error(kraus_ops): From 9ddd50c80554c431ad04de50d96b0f05d26b2eba Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 11:44:25 +0530 Subject: [PATCH 18/23] ruff fix --- toqito/channel_ops/complementary_channel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index c8f9a2a33..b5ad307db 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -82,11 +82,11 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: if (any(k.shape[0] != k.shape[1] for k in kraus_ops) and any(k.shape[0] != op_dim for k in kraus_ops)): raise ValueError("All Kraus operators must be equal size square matrices.") - + # Check the Kraus completeness relation: ∑ K_i† K_i = I identity = np.eye(op_dim, dtype=kraus_ops[0].dtype) sum_k_dagger_k = sum(k.T.conj() @ k for k in kraus_ops) - + if not np.allclose(sum_k_dagger_k, identity): raise ValueError("The Kraus operators do not satisfy the completeness relation ∑ K_i† K_i = I.") From 326b11c2c8461125a858a8a10e13e915893b58e2 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 12:27:47 +0530 Subject: [PATCH 19/23] modifying tests --- .../tests/test_complementary_channel.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index 2ed78b9ad..8bcc3b7ed 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -6,25 +6,25 @@ from toqito.channel_ops import complementary_channel # Define test cases for complementary map -kraus_1 = np.array([[1, 0], [0, 0]]) -kraus_2 = np.array([[0, 1], [0, 0]]) -kraus_3 = np.array([[0, 0], [1, 0]]) -kraus_4 = np.array([[0, 0], [0, 1]]) +kraus_1 = np.array([[0.5, 0], [0, 0]]) +kraus_2 = np.array([[0, 0.5], [0, 0]]) +kraus_3 = np.array([[0, 0], [0.5, 0]]) +kraus_4 = np.array([[0, 0], [0, 0.5]]) # Expected results for the complementary map expected_res_comp = [ - np.array([[1, 0], [0, 1], [0, 0], [0, 0]]), - np.array([[0, 0], [0, 0], [1, 0], [0, 1]]), + np.array([[0.5, 0], [0, 0.5], [0, 0], [0, 0]]), + np.array([[0, 0], [0, 0], [0.5, 0], [0, 0.5]]), ] # Higher-dimensional Kraus operators (3x3) -kraus_5 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / np.sqrt(3) -kraus_6 = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) / np.sqrt(3) +kraus_5 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 0]]) / np.sqrt(2) +kraus_6 = np.array([[0, 0, 1], [0, 0, 0], [1, 0, 0]]) / np.sqrt(2) expected_res_comp_high_dim = [ - np.array([[1, 0, 0], [0, 1, 0]]) / np.sqrt(3), - np.array([[0, 1, 0], [1, 0, 1]]) / np.sqrt(3), - np.array([[0, 0, 1], [0, 1, 0]]) / np.sqrt(3), + np.array([[1, 0, 0], [0, 0, 1]]) / np.sqrt(2), + np.array([[0, 1, 0], [0, 0, 0]]) / np.sqrt(2), + np.array([[0, 0, 0], [1, 0, 0]]) / np.sqrt(2), ] # Single Kraus operator (edge case) From 86d5dfef7814bcfd04097a9058a5c20d01b3e7a9 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 13:39:44 +0530 Subject: [PATCH 20/23] updating tests --- .../tests/test_complementary_channel.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index 8bcc3b7ed..a420d6096 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -6,25 +6,26 @@ from toqito.channel_ops import complementary_channel # Define test cases for complementary map -kraus_1 = np.array([[0.5, 0], [0, 0]]) -kraus_2 = np.array([[0, 0.5], [0, 0]]) -kraus_3 = np.array([[0, 0], [0.5, 0]]) -kraus_4 = np.array([[0, 0], [0, 0.5]]) +kraus_1 = np.array([[1, 0], [0, 0]]) / np.sqrt(2) +kraus_2 = np.array([[0, 1], [0, 0]]) / np.sqrt(2) +kraus_3 = np.array([[0, 0], [1, 0]]) / np.sqrt(2) +kraus_4 = np.array([[0, 0], [0, 1]]) / np.sqrt(2) # Expected results for the complementary map expected_res_comp = [ - np.array([[0.5, 0], [0, 0.5], [0, 0], [0, 0]]), - np.array([[0, 0], [0, 0], [0.5, 0], [0, 0.5]]), + np.array([[1, 0], [0, 1], [0, 0], [0, 0]]) / np.sqrt(2), + np.array([[0, 0], [0, 0], [1, 0], [0, 1]]) / np.sqrt(2), ] # Higher-dimensional Kraus operators (3x3) -kraus_5 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 0]]) / np.sqrt(2) -kraus_6 = np.array([[0, 0, 1], [0, 0, 0], [1, 0, 0]]) / np.sqrt(2) +kraus_5 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / np.sqrt(3) +kraus_6 = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) / np.sqrt(3) +kraus_7 = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) / np.sqrt(3) expected_res_comp_high_dim = [ - np.array([[1, 0, 0], [0, 0, 1]]) / np.sqrt(2), - np.array([[0, 1, 0], [0, 0, 0]]) / np.sqrt(2), - np.array([[0, 0, 0], [1, 0, 0]]) / np.sqrt(2), + np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) / np.sqrt(3), + np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) / np.sqrt(3), + np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) / np.sqrt(3), ] # Single Kraus operator (edge case) From f24e36bc135b8fd0b5f3e3b535ffe22b9c8653bc Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 13:54:15 +0530 Subject: [PATCH 21/23] update tests --- toqito/channel_ops/tests/test_complementary_channel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toqito/channel_ops/tests/test_complementary_channel.py b/toqito/channel_ops/tests/test_complementary_channel.py index a420d6096..01f5c49ea 100644 --- a/toqito/channel_ops/tests/test_complementary_channel.py +++ b/toqito/channel_ops/tests/test_complementary_channel.py @@ -42,7 +42,7 @@ # Test complementary_channel on a set of 2x2 Kraus operators (the ones you gave). ([kraus_1, kraus_2, kraus_3, kraus_4], expected_res_comp), # Test complementary_channel with higher-dimensional (3x3) Kraus operators. - ([kraus_5, kraus_6], expected_res_comp_high_dim), + ([kraus_5, kraus_6, kraus_7], expected_res_comp_high_dim), # Test complementary_channel with a single Kraus operator (edge case). ([kraus_single], expected_res_single), ], From aede1af4e7cb82fbcdf9dd87ae93c335dad8051b Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 14:14:25 +0530 Subject: [PATCH 22/23] update kraus op test coverage --- toqito/channel_ops/complementary_channel.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index b5ad307db..0fa672f77 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -80,9 +80,12 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: op_dim = kraus_ops[0].shape[0] - if (any(k.shape[0] != k.shape[1] for k in kraus_ops) and any(k.shape[0] != op_dim for k in kraus_ops)): - raise ValueError("All Kraus operators must be equal size square matrices.") + if any(k.shape[0] != k.shape[1] for k in kraus_ops): + raise ValueError("All Kraus operators must be square matrices.") + if any(k.shape[0] != op_dim for k in kraus_ops): + raise ValueError("All Kraus operators must be equal size matrices.") + # Check the Kraus completeness relation: ∑ K_i† K_i = I identity = np.eye(op_dim, dtype=kraus_ops[0].dtype) sum_k_dagger_k = sum(k.T.conj() @ k for k in kraus_ops) From ba0d6697c095bc08028bc7f2fc80415376176c83 Mon Sep 17 00:00:00 2001 From: Shivansh Mittal Date: Sat, 16 Nov 2024 14:15:41 +0530 Subject: [PATCH 23/23] ruff fix --- toqito/channel_ops/complementary_channel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toqito/channel_ops/complementary_channel.py b/toqito/channel_ops/complementary_channel.py index 0fa672f77..c594c4f3b 100644 --- a/toqito/channel_ops/complementary_channel.py +++ b/toqito/channel_ops/complementary_channel.py @@ -85,7 +85,7 @@ def complementary_channel(kraus_ops: list[np.ndarray]) -> list[np.ndarray]: if any(k.shape[0] != op_dim for k in kraus_ops): raise ValueError("All Kraus operators must be equal size matrices.") - + # Check the Kraus completeness relation: ∑ K_i† K_i = I identity = np.eye(op_dim, dtype=kraus_ops[0].dtype) sum_k_dagger_k = sum(k.T.conj() @ k for k in kraus_ops)