def mutual_information(state, base=2): r"""Calculate the mutual information of a bipartite state. The mutual information :math:`I` is given by: .. math:: I(\rho_{AB}) = S(\rho_A) + S(\rho_B) - S(\rho_{AB}) where :math:`\rho_A=Tr_B[\rho_{AB}], \rho_B=Tr_A[\rho_{AB}]`, are the reduced density matrices of the bipartite state :math:`\rho_{AB}`. Args: state (Statevector or DensityMatrix): a bipartite state. base (int): the base of the logarithm [Default: 2]. Returns: float: The mutual information :math:`I(\rho_{AB})`. Raises: QiskitError: if the input state is not a valid QuantumState. QiskitError: if input is not a bipartite QuantumState. """ state = _format_state(state, validate=True) if len(state.dims()) != 2: raise QiskitError("Input must be a bipartite quantum state.") rho_a = partial_trace(state, [1]) rho_b = partial_trace(state, [0]) return entropy(rho_a, base=base) + entropy(rho_b, base=base) - entropy(state, base=base)
def entanglement_of_formation(state): """Calculate the entanglement of formation of quantum state. The input quantum state must be either a bipartite state vector, or a 2-qubit density matrix. Args: state (Statevector or DensityMatrix): a 2-qubit quantum state. Returns: float: The entanglement of formation. Raises: QiskitError: if the input state is not a valid QuantumState. QiskitError: if input is not a bipartite QuantumState. QiskitError: if density matrix input is not a 2-qubit state. """ state = _format_state(state, validate=True) if isinstance(state, Statevector): # The entanglement of formation is given by the reduced state # entropy dims = state.dims() if len(dims) != 2: raise QiskitError("Input is not a bipartite quantum state.") qargs = [0] if dims[0] > dims[1] else [1] return entropy(partial_trace(state, qargs), base=2) # If input is a density matrix it must be a 2-qubit state if state.dim != 4: raise QiskitError("Input density matrix must be a 2-qubit state.") conc = concurrence(state) val = (1 + np.sqrt(1 - (conc**2))) / 2 return shannon_entropy([val, 1 - val])
def concurrence(state): r"""Calculate the concurrence of a quantum state. The concurrence of a bipartite :class:`~qiskit.quantum_info.Statevector` :math:`|\psi\rangle` is given by .. math:: C(|\psi\rangle) = \sqrt{2(1 - Tr[\rho_0^2])} where :math:`\rho_0 = Tr_1[|\psi\rangle\!\langle\psi|]` is the reduced state from by taking the :func:`~qiskit.quantum_info.partial_trace` of the input state. For density matrices the concurrence is only defined for 2-qubit states, it is given by: .. math:: C(\rho) = \max(0, \lambda_1 - \lambda_2 - \lambda_3 - \lambda_4) where :math:`\lambda _1 \ge \lambda _2 \ge \lambda _3 \ge \lambda _4` are the ordered eigenvalues of the matrix :math:`R=\sqrt{\sqrt{\rho }(Y\otimes Y)\overline{\rho}(Y\otimes Y)\sqrt{\rho}}`. Args: state (Statevector or DensityMatrix): a 2-qubit quantum state. Returns: float: The concurrence. Raises: QiskitError: if the input state is not a valid QuantumState. QiskitError: if input is not a bipartite QuantumState. QiskitError: if density matrix input is not a 2-qubit state. """ import scipy.linalg as la # Concurrence computation requires the state to be valid state = _format_state(state, validate=True) if isinstance(state, Statevector): # Pure state concurrence dims = state.dims() if len(dims) != 2: raise QiskitError("Input is not a bipartite quantum state.") qargs = [0] if dims[0] > dims[1] else [1] rho = partial_trace(state, qargs) return float(np.sqrt(2 * (1 - np.real(purity(rho))))) # If input is a density matrix it must be a 2-qubit state if state.dim != 4: raise QiskitError("Input density matrix must be a 2-qubit state.") rho = DensityMatrix(state).data yy_mat = np.fliplr(np.diag([-1, 1, 1, -1])) sigma = rho.dot(yy_mat).dot(rho.conj()).dot(yy_mat) w = np.sort(np.real(la.eigvals(sigma))) w = np.sqrt(np.maximum(w, 0.0)) return max(0.0, w[-1] - np.sum(w[0:-1]))