Source code for qkdsec.proofs.sdp

import time

import cvxpy as cp
import numpy as np

from ._types import KeyRateResult
from .channels.base import Channel
from .protocols.base import Protocol


[docs] def solve_key_rate_sdp( protocol: Protocol, channel: Channel, solver: str = "CLARABEL", ) -> KeyRateResult: dim = protocol.dim_a * protocol.dim_b rho = cp.Variable((dim, dim), symmetric=True) constraints = [rho >> 0, cp.trace(rho) == 1] obs = protocol.observables() exp = channel.expectations() for name, op in obs.items(): if name in exp: constraints.append(cp.trace(op @ rho) == exp[name]) i_b = np.eye(protocol.dim_b) pinch_ops = [np.kron(p, i_b) for p in protocol.key_projectors()] pinched = cp.Variable((dim, dim), symmetric=True) constraints.append(pinched == sum(p @ rho @ p for p in pinch_ops)) objective = cp.Minimize(cp.quantum_rel_entr(rho, pinched, quad_approx=(2, 2))) problem = cp.Problem(objective, constraints) t0 = time.time() problem.solve(solver=solver) elapsed = time.time() - t0 if problem.status not in ("optimal", "optimal_inaccurate"): return KeyRateResult( r_lower=0.0, sdp_status=problem.status or "unknown", solve_time_s=elapsed, ) sdp_bits = float(problem.value) / np.log(2.0) leak_per_pulse = protocol.leakage(channel) r_lower = max(0.0, channel.single_photon_yield() * sdp_bits - leak_per_pulse) return KeyRateResult( r_lower=r_lower, sdp_status=problem.status, solve_time_s=elapsed, )