Source code for toqito.state_props.is_abs_ppt
"""Checks if a quantum state is absolutely PPT."""
import cvxpy as cp
import numpy as np
from toqito.matrix_props import is_hermitian, is_positive_semidefinite, is_square
from toqito.state_props.abs_ppt_constraints import abs_ppt_constraints
from toqito.state_props.in_separable_ball import in_separable_ball
[docs]
def is_abs_ppt(
mat: np.ndarray | cp.Variable, dim: int | None = None, rtol: float = 1e-05, atol: float = 1e-08
) -> bool | None | list[cp.Constraint]:
r"""Determine whether or not a matrix is absolutely PPT [@Hildebrand_2007_AbsPPT].
A Hermitian positive semidefinite matrix is absolutely PPT iff it is PPT under all unitary transformations.
Equivalently, if the matrix operates on a Hilbert space \(H_{nm}\) of dimension \(nm\), then it is
PPT under *all* possible decompositions of \(H_{nm}\) as \(H_{n} \otimes H_{m}\). Being absolutely
PPT is a spectral condition (i.e. it is a condition on the eigenvalues of the matrix).
The function allows passing a `numpy` ndarray or a `cvxpy` Variable for `mat`:
- If `mat` is a `numpy` ndarray, the function first checks if `mat` is Hermitian positive
semidefinite. Then, it checks if its eigenvalues satisfy the Gerschgorin circle property (see Theorem 7.2 of
[@Jivulescu_2015_Reduction]). Then it checks if the matrix belongs to the separable ball by calling
`in_separable_ball`. Finally, if all the above checks fail to return a definite result, it determines if
the matrix is absolutely PPT by checking if all the constraint matrices returned by
`abs_ppt_constraints` are positive semidefinite.
- If `mat` is a `cvxpy` Variable, `mat` must be a 1D vector representing the eigenvalues of
a matrix. The function then returns the list of `cvxpy` Constraints required for optimizing over the
space of absolutely PPT matrices. This includes the positive semidefinite constraint on each constraint matrix
as well as `mat[0] ≥ mat[1] ≥ ... ≥ mat[-1] ≥ 0`.
This function is adapted from QETLAB [@QETLAB_link].
!!! Note
If `min(dim)` \(\leq 6\), this function checks all constraints
and therefore returns `True` or `False` in all cases. However, if
`min(dim)` \(\geq 7\), only the first \(33592\) constraints are
checked, since there are over \(23178480\) constraints in this case
[@Johnston_2014_Orderings]. Therefore the function returns either
`False` if at least one constraint was not satisfied, or `None`
if all checked constraints were satisfied.
Examples:
A random density matrix will likely not be absolutely PPT:
```python exec="1" source="above"
import numpy as np
from toqito.rand import random_density_matrix
from toqito.state_props import is_abs_ppt
rho = random_density_matrix(9) # assumed to act on a 3 x 3 bipartite system
print(f"ρ is absolutely PPT: {is_abs_ppt(rho, 3)}")
```
The maximally-mixed state is an example of an absolutely PPT state:
```python exec="1" source="above"
import numpy as np
from toqito.states import max_mixed
from toqito.state_props import is_abs_ppt
rho = max_mixed(9) # assumed to act on a 3 x 3 bipartite system
print(f"ρ is absolutely PPT: {is_abs_ppt(rho, 3)}")
```
Raises:
TypeError: If `mat` is not a `numpy` ndarray or a `cvxpy` Variable.
ValueError: If `mat` is a `numpy` ndarray but is not square.
ValueError: If `mat` is a `cvxpy` Variable but is not 1D.
ValueError: If `dim` does not divide the dimensions of `mat`.
Args:
mat: A square matrix.
dim: The dimension of any one subsystem on which `mat` acts. If `None`, `dim` is selected such that
`min(dim, mat.shape[0] // dim)` is maximised, since this gives the strongest conditions on being absolutely PPT
(see Theorem 2 of [@Hildebrand_2007_AbsPPT]).
rtol: The relative tolerance parameter (default 1e-05).
atol: The absolute tolerance parameter (default 1e-08).
Returns:
If `mat` is a 1D `cvxpy` Variable, return a list of `cvxpy` Constraints required for optimizing over the space
of absolutely PPT matrices.
"""
if isinstance(mat, np.ndarray):
if not is_square(mat):
raise ValueError(f"Expected mat to be square: however mat.shape was {mat.shape}")
elif isinstance(mat, cp.Variable):
if mat.ndim != 1:
raise ValueError(f"Expected mat to be 1D: however mat had {mat.ndim} dimensions")
else:
raise TypeError("mat must be a square numpy ndarray or a 1D cvxpy Variable")
nm = mat.shape[0]
if dim is None:
# Find the largest divisor d of nm such that d ** 2 <= nm.
# nm won't be too large, so let's just use a for-loop.
# Floating-point arithmetic is risky.
dim, j = 1, 1
while True:
if j**2 > nm:
break
if nm % j == 0:
dim = j
j += 1
if nm % dim != 0:
raise ValueError("Calculated subsystem dimensions and provided matrix dimensions are incompatible")
n, m = dim, nm // dim
p = min(n, m)
if isinstance(mat, np.ndarray):
# Quick checks:
# 1. Check if mat is Hermitian.
if not is_hermitian(mat, rtol, atol):
return False
# Compute eigenvalues (in descending order).
# np.linalg.eigsvalsh normally returns eigenvalues in ascending order,
# but it is risky to assume this will remain the default behaviour in the future.
eigs = np.sort(np.linalg.eigvalsh(mat))[::-1]
# 2. Check if mat is PSD.
if eigs[-1] < -abs(atol):
return False
# 3. Check Theorem 7.2 of [@Jivulescu_2015_Reduction].
if sum(eigs[: p - 1]) <= eigs[-1] + sum(eigs[-p:]):
return True
# 4. Check if mat is in separable ball.
if in_separable_ball(mat):
return True
# All quick checks failed, so construct constraint matrices and check if all are PSD.
constraints = abs_ppt_constraints(eigs, p)
for constraint in constraints:
if not is_positive_semidefinite(constraint, rtol, atol):
return False
# We checked all constraints for p <= 6, but not for p >= 7.
return True if p <= 6 else None
else:
constraints = abs_ppt_constraints(mat, p, use_check=True)
return [mat[-1] >= 0] + [mat[i] >= mat[i + 1] for i in range(nm - 1)] + [c_mat >> 0 for c_mat in constraints]