Source code for toqito.matrix_props.is_absolutely_k_incoherent

"""Checks if the matrix is absolutely $k$-incoherent."""

import cvxpy as cp
import numpy as np

from toqito.matrix_props import is_positive_semidefinite, is_square


[docs] def is_absolutely_k_incoherent(mat: np.ndarray, k: int, tol: float = 1e-15) -> bool: r"""Determine whether a quantum state is absolutely k-incoherent [@Johnston_2022_Absolutely]. Formally, for positive integers \(n\) and \(k\), a mixed quantum state is said to be absolutely k-incoherent if \(U \rho U^* \in \mathbb{I}_{k, n}\) for all unitary matrices \(U \in \text{U}(\mathbb{C}^n)\). This function checks if the provided density matrix is absolutely k-incoherent based on the criteria introduced in [@Johnston_2022_Absolutely] and the corresponding QETLAB functionality [@QETLAB_link]. When necessary, an SDP is set up via ``cvxpy``. The notion of absolute k-incoherence is connected to the notion of quantum state antidistinguishability as discussed in [@Johnston_2025_Tight]. Examples: ```python exec="1" source="above" import numpy as np from toqito.matrix_props import is_absolutely_k_incoherent mat = np.array([[2, 1, 2], [1, 2, -1], [2, -1, 5]]) print(is_absolutely_k_incoherent(mat, 4)) ``` !!! See [is_antidistinguishable()][toqito.state_props.is_antidistinguishable.is_antidistinguishable], [is_k_incoherent()][toqito.matrix_props.is_k_incoherent.is_k_incoherent] Raises: ValueError: If the input matrix is not square. Args: mat: Matrix to check for absolute k-incoherence. k: The positive integer indicating the absolute coherence level. tol: Tolerance for numerical comparisons (default is 1e-15). Returns: True if the quantum state is absolutely k-incoherent, False otherwise. """ if k <= 0: raise ValueError("k must be a positive integer.") if not is_square(mat): raise ValueError("Input matrix must be square.") n = mat.shape[0] # Trivial: every matrix is absolutely k-incoherent for k >= n. if k >= n: return True # Check that the input matrix is a valid density matrix. if not (is_positive_semidefinite(mat) and np.isclose(np.trace(mat), 1, atol=tol)): return False # Compute eigenvalues and rank. eigvals = np.linalg.eigvalsh(mat) rankX = np.linalg.matrix_rank(mat, tol=tol) lmax = np.max(eigvals) # Trivial: only the maximally mixed state is absolutely 1-incoherent. if k == 1: if np.all(np.abs(eigvals - (1 / n)) <= tol): return True else: return False # [1] Theorem 4: Check rank conditions. if rankX <= n - k: return False elif rankX == n - k + 1: # Check if all nonzero eigenvalues are approximately equal. nonzero = eigvals[np.abs(eigvals) > tol] if len(nonzero) > 0 and np.all(np.abs(nonzero - nonzero[0]) <= tol): return True # [1] Theorem 5: Check if the largest eigenvalue meets the condition. if lmax <= 1 / (n - k + 1): return True if k == 2: # [1] Theorem 7: Use the Frobenius norm condition. frob_norm_sq = np.linalg.norm(mat, "fro") ** 2 if frob_norm_sq <= 1 / (n - 1): return True elif n <= 3: return False elif k == n - 1: # [1] Corollary 1: Check maximum eigenvalue condition. if lmax > 1 - 1 / n: return False else: # [1] Theorem 8: Solve an SDP to decide absolute (n-1)-incoherence. lam = np.sort(np.real(eigvals))[::-1] n_eig = len(lam) L = cp.Variable((n_eig, n_eig), symmetric=True) constraints = [] # Constraint: L[0, 0] == -lam[0] - sum(L[0, 1:]) - sum(L[1:, 0]) constraints.append(L[0, 0] == -lam[0] - cp.sum(L[0, 1:]) - cp.sum(L[1:, 0])) # For indices j = 1 to n_eig-1, enforce L[j, j] == lam[j] for j in range(1, n_eig): constraints.append(L[j, j] == lam[j]) # L must be positive semidefinite. constraints.append(L >> 0) # Dummy objective function. objective = cp.Minimize(1) prob = cp.Problem(objective, constraints) opt_val = prob.solve(solver=cp.SCS, verbose=False) if np.isclose(opt_val, 1.0): return True return False