Source code for toqito.perms.antisymmetric_projection

"""Antisymmetric projection operator produces an orthogonal projection onto an anti-symmetric subspace."""

from itertools import permutations

import numpy as np

from toqito.perms import perm_sign, permutation_operator


[docs] def antisymmetric_projection(dim: int, p_param: int = 2, partial: bool = False) -> np.ndarray: r"""Produce the projection onto the antisymmetric subspace [@WikiAsymmOp]. Produces the orthogonal projection onto the anti-symmetric subspace of `p_param` copies of `dim`-dimensional space. If `partial = True`, then the antisymmetric projection (PA) isn't the orthogonal projection itself, but rather a matrix whose columns form an orthonormal basis for the symmetric subspace (and hence the PA * PA' is the orthogonal projection onto the symmetric subspace.) Examples: The \(2\)-dimensional antisymmetric projection with \(p=1\) is given as \(2\)-by-\(2\) identity matrix \[ A_{2,1} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}. \] Using `|toqito⟩`, we can see this gives the proper result. ```python exec="1" source="above" from toqito.perms import antisymmetric_projection print(antisymmetric_projection(2, 1)) ``` When the \(p\) value is greater than the dimension of the antisymmetric projection, this just gives the matrix consisting of all zero entries. For instance, when \(d = 2\) and \(p = 3\) we have that \[ A_{2, 3} = \begin{pmatrix} 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \end{pmatrix}. \] Using `|toqito⟩` we can see this gives the proper result. ```python exec="1" source="above" from toqito.perms import antisymmetric_projection print(antisymmetric_projection(2, 3)) ``` Args: dim: The dimension of the local systems. p_param: Default value of 2. partial: Default value of 0. Returns: Projection onto the antisymmetric subspace. """ dimp = dim**p_param if p_param == 1: return np.eye(dim) # The antisymmetric subspace is empty if `dim < p`. if dim < p_param: return np.zeros((dimp, dimp * (1 - partial))) p_list = np.array(list(permutations(np.arange(p_param)))) p_fac = p_list.shape[0] anti_proj = np.zeros((dimp, dimp)) for j in range(p_fac): anti_proj += perm_sign(p_list[j, :]) * permutation_operator(dim * np.ones(p_param), p_list[j, :], False, True) anti_proj = anti_proj / p_fac if partial: anti_proj = np.array(np.linalg.qr(anti_proj)) return anti_proj