Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upated Indexing from 1 -> 0 #602

Merged
merged 18 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions toqito/channel_metrics/fidelity_of_separability.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def fidelity_of_separability(
raise ValueError("This function only works for pure states.")

# We first permure psi_{BAR} to psi_{RAB} to simplify the code.
psi = permute_systems(psi, [3, 2, 1], psi_dims)
psi = permute_systems(psi, [2, 1, 0], psi_dims)
dim_b, dim_a, dim_r = psi_dims
psi_dims = [dim_r, dim_a, dim_b]

Expand Down Expand Up @@ -163,7 +163,7 @@ def fidelity_of_separability(
pi_sym
* picos.partial_trace(
(picos.partial_transpose(psi, [0], psi_dims) @ picos.I(dim_a))
* permute_systems(choi_partial @ picos.I(dim_b * dim_a), [1, 4, 3, 2], dim_list),
* permute_systems(choi_partial @ picos.I(dim_b * dim_a), [0, 3, 2, 1], dim_list),
[0, 2],
dim_list,
)
Expand Down
2 changes: 1 addition & 1 deletion toqito/channel_ops/partial_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def partial_channel(

phi_map = permute_systems(
np.kron(np.kron(psi_r1 * psi_c1.conj().T, phi_map), psi_r2 * psi_c2.conj().T),
[1, 3, 5, 2, 4, 6],
[0, 2, 4, 1, 3, 5],
dim,
)

Expand Down
4 changes: 2 additions & 2 deletions toqito/channels/partial_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,10 @@ def partial_trace(
sys = np.array(sys)
if isinstance(sys, int):
sys = np.array([sys])
set_diff = list(set(list(range(1, num_sys + 1))) - set(sys + 1))

set_diff = list(set(list(range(0, num_sys))) - set(sys))
anushkrishnav marked this conversation as resolved.
Show resolved Hide resolved
perm = set_diff
perm.extend(sys + 1)
perm.extend(sys)

a_mat = permute_systems(input_mat, perm, dim)

Expand Down
6 changes: 3 additions & 3 deletions toqito/channels/partial_transpose.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ def partial_transpose(
sub_sys_vec_r = prod_dim_r * np.ones(int(sub_prod_r)) / sub_prod_r
sub_sys_vec_c = prod_dim_c * np.ones(int(sub_prod_c)) / sub_prod_c

set_diff = list(set(list(range(1, num_sys + 1))) - set(sys + 1))
perm = (sys + 1).tolist()[:]
set_diff = list(set(list(range(0, num_sys ))) - set(sys ))
anushkrishnav marked this conversation as resolved.
Show resolved Hide resolved
perm = (sys ).tolist()[:]
perm.extend(set_diff)

# Permute the subsystems so that we just have to do the partial transpose
Expand Down Expand Up @@ -198,6 +198,6 @@ def partial_transpose(
# Return the subsystems back to their original positions.
dim[:, sys] = np.flipud(dim[:, sys])

dim = dim[:, (np.array(perm) - 1).tolist()]
dim = dim[:, (np.array(perm) ).tolist()]

return permute_systems(z_tmp, perm, dim, False, True)
4 changes: 2 additions & 2 deletions toqito/nonlocal_games/quantum_hedging.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ def __init__(self, q_a: np.ndarray, num_reps: int) -> None:
# action:
# π(y1 ⊗ y2 ⊗ x1 ⊗ x2) = y1 ⊗ x1 ⊗ y2 ⊗ x2
# for all y1 ∈ Y1, y2 ∈ Y2, x1 ∈ X1, x2 ∈ X2.).
l_1 = list(range(1, self._num_reps + 1))
l_2 = list(range(self._num_reps + 1, self._num_reps**2 + 1))
l_1 = list(range(0, self._num_reps ))
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
l_2 = list(range(self._num_reps , self._num_reps**2 ))
if self._num_reps == 1:
self._pperm = np.array([1])
else:
Expand Down
2 changes: 1 addition & 1 deletion toqito/perms/antisymmetric_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def antisymmetric_projection(dim: int, p_param: int = 2, partial: bool = False)
if dim < p_param:
return np.zeros((dimp, dimp * (1 - partial)))

p_list = np.array(list(permutations(np.arange(1, p_param + 1))))
p_list = np.array(list(permutations(np.arange(0, p_param ))))
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
p_fac = p_list.shape[0]

anti_proj = np.zeros((dimp, dimp))
Expand Down
14 changes: 7 additions & 7 deletions toqito/perms/perfect_matchings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@ def perfect_matchings(num: list[int] | int | np.ndarray) -> np.ndarray:

Examples
==========

This is an example of how to generate all perfect matchings of the numbers 1, 2, 3, 4.
This is an example of how to generate all perfect matchings of the numbers 0, 1, 2, 3.

>>> from toqito.perms import perfect_matchings
>>> perfect_matchings(4)
array([[1, 2, 3, 4],
[1, 3, 2, 4],
[1, 4, 3, 2]])
array([[0, 1, 2, 3],
[0, 2, 1, 3],
[0, 3, 2, 1]])

References
==========
.. bibliography::
:filter: docname in docnames

:param num: Either an even integer, indicating that you would like all perfect matchings of the
integers 1,2, ... N, or a `list` or `np.array` containing an even number of distinct
integers 0, 1, ... N-1, or a `list` or `np.array` containing an even number of distinct
entries, indicating that you would like all perfect matchings of those entries.
:return: An array containing all valid perfect matchings of size :code:`num`.

"""
if isinstance(num, int):
num = np.arange(1, num + 1)
num = np.arange(num)
if isinstance(num, list):
num = np.array(num)

Expand Down Expand Up @@ -73,3 +72,4 @@ def perfect_matchings(num: list[int] | int | np.ndarray) -> np.ndarray:
matchings = np.vstack((matchings, s_vec))

return matchings

8 changes: 4 additions & 4 deletions toqito/perms/permutation_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def permutation_operator(
qubits

.. math::
P_{2, [2, 1]} =
P_{2, [1, 0]} =
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 \\
Expand All @@ -38,13 +38,12 @@ def permutation_operator(
Using :code:`toqito`, this can be achieved in the following manner.

>>> from toqito.perms import permutation_operator
>>> permutation_operator(2, [2, 1])
>>> permutation_operator(2, [1, 0])
array([[1., 0., 0., 0.],
[0., 0., 1., 0.],
[0., 1., 0., 0.],
[0., 0., 0., 1.]])


:param dim: The dimensions of the subsystems to be permuted.
:param perm: A permutation vector.
:param inv_perm: Boolean dictating if :code:`perm` is inverse or not.
Expand All @@ -54,10 +53,11 @@ def permutation_operator(
"""
# Allow the user to enter a single number for `dim`.
if isinstance(dim, int):
dim = dim * np.ones(max(perm))
dim = [dim] * len(perm)
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(dim, list):
dim = np.array(dim)

mat = sp.sparse.identity(int(np.prod(dim))) if is_sparse else np.identity(int(np.prod(dim)))
# Swap the rows of the identity matrix appropriately.
anushkrishnav marked this conversation as resolved.
Show resolved Hide resolved

return permute_systems(mat, perm, dim, True, inv_perm)
19 changes: 12 additions & 7 deletions toqito/perms/permute_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def permute_systems(

For spaces :math:`\mathcal{A}` and :math:`\mathcal{B}` where :math:`\text{dim}(\mathcal{A}) =
\text{dim}(\mathcal{B}) = 2` we may consider an operator :math:`X \in \mathcal{A} \otimes \mathcal{B}`. Applying the
`permute_systems` function with vector :math:`[2,1]` on :math:`X`, we may reorient the spaces such that :math:`X \in
`permute_systems` function with vector :math:`[1,0]` on :math:`X`, we may reorient the spaces such that :math:`X \in
\mathcal{B} \otimes \mathcal{A}`.

For example, if we define :math:`X \in \mathcal{A} \otimes \mathcal{B}` as
Expand All @@ -53,7 +53,7 @@ def permute_systems(
yield the following matrix

.. math::
X_{[2,1]} = \begin{pmatrix}
X_{[1,0]} = \begin{pmatrix}
1 & 3 & 2 & 4 \\
9 & 11 & 10 & 12 \\
5 & 7 & 6 & 8 \\
Expand All @@ -63,15 +63,15 @@ def permute_systems(
>>> from toqito.perms import permute_systems
>>> import numpy as np
>>> test_input_mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
>>> permute_systems(test_input_mat, [2, 1])
>>> permute_systems(test_input_mat, [1, 0])
array([[ 1, 3, 2, 4],
[ 9, 11, 10, 12],
[ 5, 7, 6, 8],
[13, 15, 14, 16]])

For spaces :math:`\mathcal{A}, \mathcal{B}`, and :math:`\mathcal{C}` where :math:`\text{dim}(\mathcal{A}) =
\text{dim}(\mathcal{B}) = \text{dim}(\mathcal{C}) = 2` we may consider an operator :math:`X \in \mathcal{A} \otimes
\mathcal{B} \otimes \mathcal{C}`. Applying the :code:`permute_systems` function with vector :math:`[2,3,1]` on
\mathcal{B} \otimes \mathcal{C}`. Applying the :code:`permute_systems` function with vector :math:`[1,2,0]` on
:math:`X`, we may reorient the spaces such that :math:`X \in \mathcal{B} \otimes \mathcal{C} \otimes \mathcal{A}`.

For example, if we define :math:`X \in \mathcal{A} \otimes \mathcal{B} \otimes \mathcal{C}` as
Expand All @@ -93,7 +93,7 @@ def permute_systems(
\otimes \mathcal{C}` yield the following matrix

.. math::
X_{[2, 3, 1]} =
X_{[1, 2, 0]} =
\begin{pmatrix}
1 & 5 & 2 & 6 & 3 & 7 & 4, 8 \\
33 & 37 & 34 & 38 & 35 & 39 & 36 & 40 \\
Expand All @@ -119,7 +119,7 @@ def permute_systems(
... [57, 58, 59, 60, 61, 62, 63, 64],
... ]
... )
>>> permute_systems(test_input_mat, [2, 3, 1])
>>> permute_systems(test_input_mat, [1, 2, 0])
array([[ 1, 5, 2, 6, 3, 7, 4, 8],
[33, 37, 34, 38, 35, 39, 36, 40],
[ 9, 13, 10, 14, 11, 15, 12, 16],
Expand All @@ -145,6 +145,7 @@ def permute_systems(
else:
input_mat_dims = input_mat.shape


is_vec = np.min(input_mat_dims) == 1
num_sys = len(perm)

Expand Down Expand Up @@ -176,7 +177,7 @@ def permute_systems(
prod_dim_r = int(np.prod(dim[0, :]))
prod_dim_c = int(np.prod(dim[1, :]))

if sorted(perm) != list(range(1, num_sys + 1)):
if sorted(perm) != list(range(0, num_sys )):
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("InvalidPerm: `perm` must be a permutation vector.")
if input_mat_dims[0] != prod_dim_r or (not row_only and input_mat_dims[1] != prod_dim_c):
raise ValueError("InvalidDim: The dimensions specified in DIM do not agree with the size of X.")
Expand All @@ -185,6 +186,10 @@ def permute_systems(
if input_mat.shape[0] == 1:
input_mat = input_mat[0]
vec_orien = 1
# Rather than using subtraction to generate new indices,
# it's better to use methods designed for handling permutations directly.
# This avoids the risk of negative indices and is more straightforward.
num_sys -= 1 # 0-indexing (Since we're using 0-indexing, we need to subtract 1 from the number of subsystems.)
permuted_mat_1 = input_mat.reshape(dim[vec_orien, ::-1].astype(int), order="F")
if inv_perm:
permuted_mat = vec(np.transpose(permuted_mat_1, np.argsort(num_sys - np.array(perm[::-1])))).T
Expand Down
2 changes: 1 addition & 1 deletion toqito/perms/swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def swap(
raise ValueError("InvalidSys: `sys` must be a vector with exactly two elements.")

# Swap the indicated subsystems.
perm = np.array(range(1, num_sys + 1))
perm = np.array(range(0, num_sys ))
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
sys = np.array(sys) - 1

perm[sys] = perm[sys[::-1]]
Expand Down
2 changes: 1 addition & 1 deletion toqito/perms/symmetric_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def symmetric_projection(dim: int, p_val: int = 2, partial: bool = False) -> [np
if p_val == 1:
return np.eye(dim)

p_list = np.array(list(permutations(np.arange(1, p_val + 1))))
p_list = np.array(list(permutations(np.arange(0, p_val ))))
purva-thakre marked this conversation as resolved.
Show resolved Hide resolved
p_fac = math.factorial(p_val)
sym_proj = np.zeros((dimp, dimp))

Expand Down
38 changes: 20 additions & 18 deletions toqito/perms/tests/test_perfect_matchings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
def test_perfect_matchings_num_4():
"""All perfect matchings of size 4."""
res = perfect_matchings(4)
expected_res = np.array([[1, 2, 3, 4], [1, 3, 2, 4], [1, 4, 3, 2]])
print(res)
anushkrishnav marked this conversation as resolved.
Show resolved Hide resolved
expected_res = np.array([[0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 2, 1]])
bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)


def test_perfect_matchings_num_4_list():
"""All perfect matchings of size 4 with input as list."""
res = perfect_matchings([1, 2, 3, 4])
expected_res = np.array([[1, 2, 3, 4], [1, 3, 2, 4], [1, 4, 3, 2]])
res = perfect_matchings([0, 1, 2, 3])
expected_res = np.array([[0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 2, 1]])
bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)

Expand All @@ -32,24 +33,25 @@ def test_perfect_matchings_odd():
def test_perfect_matchings_num_6():
"""All perfect matchings of size 6."""
res = perfect_matchings(6)
print(res)
anushkrishnav marked this conversation as resolved.
Show resolved Hide resolved

expected_res = np.array(
[
[1, 2, 3, 4, 5, 6],
[1, 2, 3, 5, 4, 6],
[1, 2, 3, 6, 5, 4],
[1, 3, 2, 4, 5, 6],
[1, 3, 2, 5, 4, 6],
[1, 3, 2, 6, 5, 4],
[1, 4, 3, 2, 5, 6],
[1, 4, 3, 5, 2, 6],
[1, 4, 3, 6, 5, 2],
[1, 5, 3, 4, 2, 6],
[1, 5, 3, 2, 4, 6],
[1, 5, 3, 6, 2, 4],
[1, 6, 3, 4, 5, 2],
[1, 6, 3, 5, 4, 2],
[1, 6, 3, 2, 5, 4],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 4, 3, 5],
[0, 1, 2, 5, 4, 3],
[0, 2, 1, 3, 4, 5],
[0, 2, 1, 4, 3, 5],
[0, 2, 1, 5, 4, 3],
[0, 3, 2, 1, 4, 5],
[0, 3, 2, 4, 1, 5],
[0, 3, 2, 5, 4, 1],
[0, 4, 2, 3, 1, 5],
[0, 4, 2, 1, 3, 5],
[0, 4, 2, 5, 1, 3],
[0, 5, 2, 3, 4, 1],
[0, 5, 2, 4, 3, 1],
[0, 5, 2, 1, 4, 3]
]
)
bool_mat = np.isclose(res, expected_res)
Expand Down
36 changes: 18 additions & 18 deletions toqito/perms/tests/test_permutation_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@


def test_permutation_operator_standard_swap():
"""Generates the standard swap operator on two qubits."""
"""Generates the standard swap operator on two qubits with zero-based indexing."""
expected_res = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])

res = permutation_operator(2, [2, 1])
res = permutation_operator(2, [1, 0])

bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_standard_swap_list_dim():
"""Generates the standard swap operator on two qubits."""
"""Generates the standard swap operator on two qubits with zero-based indexing."""
expected_res = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])

res = permutation_operator([2, 2], [2, 1])
res = permutation_operator([2, 2], [1, 0])

bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_sparse_option():
"""Sparse swap operator on two qutrits."""
res = permutation_operator(3, [2, 1], False, True)
"""Sparse swap operator on two qutrits with zero-based indexing."""
res = permutation_operator(3, [1, 0], False, True)

expected_res = np.array(
[
Expand All @@ -46,17 +46,17 @@ def test_permutation_operator_sparse_option():
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_dim_3_perm_1_2():
"""Test permutation operator when dim is 3 and perm is [1, 2]."""
res = permutation_operator(3, [1, 2])
def test_permutation_operator_dim_3_perm_0_1():
"""Test permutation operator when dim is 3 and perm is [0, 1] using zero-based indexing."""
res = permutation_operator(3, [0, 1])
expected_res = np.identity(9)
bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_dim_2_perm_1_3_2():
"""Test permutation operator when dim is 2 and perm is [1, 3, 2]."""
res = permutation_operator(2, [1, 3, 2])
def test_permutation_operator_dim_2_perm_0_2_1():
"""Test permutation operator when dim is 2 and perm is [0, 2, 1] using zero-based indexing."""
res = permutation_operator(2, [0, 2, 1])
expected_res = np.array(
[
[
Expand All @@ -75,17 +75,17 @@ def test_permutation_operator_dim_2_perm_1_3_2():
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_dim_2_2_perm_1_2():
"""Test permutation operator when dim is [2, 2] and perm is [1, 2]."""
res = permutation_operator([2, 2], [1, 2])
def test_permutation_operator_dim_2_2_perm_0_1():
"""Test permutation operator when dim is [2, 2] and perm is [0, 1] using zero-based indexing."""
res = permutation_operator([2, 2], [0, 1])
expected_res = np.identity(4)
bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)


def test_permutation_operator_dim_2_2_perm_2_1():
"""Test permutation operator when dim is [2, 2] and perm is [2, 1]."""
res = permutation_operator([2, 2], [2, 1])
def test_permutation_operator_dim_2_2_perm_1_0():
"""Test permutation operator when dim is [2, 2] and perm is [1, 0] using zero-based indexing."""
res = permutation_operator([2, 2], [1, 0])
expected_res = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])
bool_mat = np.isclose(res, expected_res)
np.testing.assert_equal(np.all(bool_mat), True)
Loading
Loading