Source code for toqito.channel_metrics.completely_bounded_trace_norm

"""Computes the completely bounded trace norm of a quantum channel."""

import numpy as np
import picos as pc

from toqito.channel_ops import apply_channel, dual_channel
from toqito.channel_props import is_completely_positive, is_quantum_channel
from toqito.matrix_props import trace_norm


[docs] def completely_bounded_trace_norm(phi: np.ndarray, solver: str = "cvxopt", **kwargs) -> float | np.floating: r"""Find the completely bounded trace norm of a quantum channel. Also known as the diamond norm of a quantum channel (Section 3.3.2 of [@Watrous_2018_TQI]). The algorithm in p.11 of [@Watrous_2012_Simpler] with implementation in QETLAB [@QETLAB_link] is used. Examples: To compute the completely bounded trace norm of a depolarizing channel: ```python exec="1" source="above" from toqito.channels import depolarizing from toqito.channel_metrics import completely_bounded_trace_norm # Define the depolarizing channel choi_depolarizing = depolarizing(dim=2, param_p=0.2) print(completely_bounded_trace_norm(choi_depolarizing)) ``` Raises: ValueError: If matrix is not square. Args: phi: superoperator as choi matrix solver: Optimization option for `picos` solver. Default option is `solver="cvxopt"`. kwargs: Additional arguments to pass to picos' solve method. Returns: The completely bounded trace norm of the channel """ dim_lx, dim_ly = phi.shape if dim_lx != dim_ly: raise ValueError("The input and output spaces of the superoperator phi must both be square.") if is_quantum_channel(phi): return 1 if is_completely_positive(phi): v = apply_channel(np.eye(dim_ly), dual_channel(phi)) return trace_norm(v) dim = round(np.sqrt(dim_lx)) # SDP sdp = pc.Problem() y0 = pc.HermitianVariable("y0", (dim_lx, dim_lx)) sdp.add_constraint(y0 >> 0) y1 = pc.HermitianVariable("y1", (dim_lx, dim_lx)) sdp.add_constraint(y1 >> 0) a_var = pc.block([[y0, -phi], [-phi.conj().T, y1]]) sdp.add_constraint(a_var >> 0) obj = pc.SpectralNorm(y0.partial_trace(1, dimensions=dim)) + pc.SpectralNorm(y1.partial_trace(1, dimensions=dim)) sdp.set_objective("min", obj) sdp.solve(solver=solver, **kwargs) return sdp.value / 2