Source code for dbac.hbac

"""
hbac.py

Heat-bath algorithmic cooling (HBAC) baseline used for comparison against
DBAC. HBAC repeatedly SWAPs entropy onto a fresh, highly-polarized "reset"
qubit and discards it, compressing the joint state towards its ground state
one qubit at a time.
"""

__all__ = ["refresh_reset_qubit", "compress_density_matrix", "hbac"]

import numpy as np

from dbac.dme import ptrace


[docs] def refresh_reset_qubit(rho, epsilon_b): """ Reset the last qubit of a joint density matrix to a thermal state with polarization `epsilon_b`, by rescaling each 2x2 block of `rho` that acts on that qubit. Parameters: rho (ndarray): 2^n x 2^n density matrix of n qubits. epsilon_b (float): Polarization of the reset qubit. Returns: ndarray: New density matrix after resetting the last qubit. """ d = rho.shape[0] assert rho.shape == (d, d), "Input must be a square matrix" assert (d & (d - 1)) == 0, "Dimension must be a power of 2" num_blocks = d // 2 # since each M_ij is 2x2 new_rho = np.zeros_like(rho, dtype=complex) thermal_matrix = np.array([ [(1 + epsilon_b) / 2, 0], [0, (1 - epsilon_b) / 2], ]) for i in range(num_blocks): for j in range(num_blocks): row_start, row_end = i * 2, i * 2 + 2 col_start, col_end = j * 2, j * 2 + 2 m_ij = rho[row_start:row_end, col_start:col_end] new_rho[row_start:row_end, col_start:col_end] = np.trace(m_ij) * thermal_matrix return new_rho
[docs] def compress_density_matrix(rho): """ Sort-and-compress step of HBAC: reorder the populations of `rho` in descending order, discarding coherences, to approximate the state achievable by the optimal (sorting) unitary. Parameters: rho (ndarray): Density matrix (Hermitian, positive semidefinite, trace 1). Returns: ndarray: Diagonal density matrix with sorted probabilities. """ assert rho.shape[0] == rho.shape[1], "Matrix must be square" assert np.allclose(rho, rho.conj().T), "Matrix must be Hermitian" probs = np.real(np.diag(rho)) sorted_probs = np.sort(probs)[::-1] return np.diag(sorted_probs)
[docs] def hbac(rho, epsilon_b=0.8, step=1): """ Run `step` rounds of heat-bath algorithmic cooling (reset + compress) on `rho`, then trace out every qubit except the first (the target qubit, which the sorting step cools). Parameters: rho (ndarray): 2^n x 2^n density matrix, last qubit is the reset qubit. epsilon_b (float): Polarization of the fresh reset qubit each round, i.e. populations ``(1 +- epsilon_b) / 2``. step (int): Number of reset-and-compress rounds. Returns: ndarray: 2x2 reduced density matrix of the first qubit. Example: >>> import numpy as np >>> from dbac.hbac import hbac >>> mixed = np.eye(2) / 2 # maximally mixed qubit >>> rho = np.kron(np.kron(mixed, mixed), mixed) >>> hbac(rho, epsilon_b=0.8, step=6).real.round(3) array([[0.985, 0. ], [0. , 0.015]]) """ for _ in range(step): rho = refresh_reset_qubit(rho, epsilon_b) rho = compress_density_matrix(rho) d = rho.shape[0] return ptrace(rho, index=1, n1=2, n2=int(d / 2))