def test_maxima_first_coherent_information_dephrasure(): r""" Test maxima of first coh-info of dephrasure channel is mixed state and matches paper.""" def optima_mixed_state_bound(p): # Bound for when coherent information is maximized by maximally mixed state. a = (1. - 2. * p - 2. * p * (1. - p) * np.log((1. - p) / p)) return a / (2. - 4. * p - 2. * p * (1. - p) * np.log((1. - p) / p)) desired = np.array([[0.5, 0.], [0., 0.5]]) for p in np.arange(0.01, 0.5, 0.1): for q in np.arange(0., optima_mixed_state_bound(p), 0.1): # Set up actual results. single_krauss_ops = set_up_dephrasure_conditions(p, q) channel = AnalyticQChan(single_krauss_ops, [1, 1], 2, 3, [2]) actual = channel.optimize_coherent(n=1, rank=2, param="overparam", maxiter=15) # Test optimal coherent information value. desired_fun = (1. - 2. * q) * (-np.log2(0.5)) - (1. - q) * \ (-(1 - p) * np.log2(1 - p) - p * np.log2(p)) assert np.abs(actual["optimal_val"] - desired_fun) < 1e-5 # Test optimal density state is the maximally mixed state. assert_array_almost_equal(desired, actual["optimal_rho"], decimal=3)
def test_optimizing_coherent_information_bit_flip_channels_only_on_one_case(): r"""Test optimizing once coherent information with an analytic example for bit-flip channel.""" err = 0.1 krauss_1 = np.array([[1., 0.], [0., 1]], dtype=np.complex128) * np.sqrt(1 - err) krauss_2 = np.array([[0., 1], [1., 0.]], dtype=np.complex128) * np.sqrt(err) krauss_ops = [krauss_1, krauss_2] desired = 1 + np.log2(err) * err + np.log2(1 - err) * (1 - err) # Kraus Operators for n in range(1, 3): channel = AnalyticQChan(krauss_ops, [1, 1], 2, 2) actual = channel.optimize_coherent(n=n, rank=2**n, param="cholesky", maxiter=100, regularized=True) assert np.abs(actual["optimal_val"] - desired) < 1e-3 # Test downgrading a n. actual = channel.optimize_coherent(n=1, rank=2, param="overparam", maxiter=100) assert np.abs(actual["optimal_val"] - desired) < 1e-3 # Choi matrices choi_mat = sum([ np.outer(np.ravel(x, order="F"), np.conj(np.ravel(x, order="F"))) for x in krauss_ops ]) chan = AnalyticQChan(choi_mat, [1, 1], 2, 2) actual = chan.optimize_coherent(n=1, rank=2, param="overparam", maxiter=100) assert np.abs(actual["optimal_val"] - desired) < 1e-3 assert_raises(AssertionError, chan.optimize_coherent, 2, 2)
def compare_lipschitz_slsqp_with_diffev(): n = 3 for p in np.arange(0.05, 0.5, 0.01): for q in np.arange(0.3, 0.5, 0.01): single_krauss_ops = set_up_dephrasure_conditions(p, q) orthogonal_krauss_indices = [2] channel = AnalyticQChan(single_krauss_ops, [1, 1], 2, 3, orthogonal_krauss_indices) diffev = channel.optimize_coherent(n, 2**n, "diffev", maxiter=500, lipschitz=10) slsqp = channel.optimize_coherent(n, 2**n, "slsqp", lipschitz=20, maxiter=100, use_pool=True) # Test optimal coherent information is the same inbetween both of them. assert np.abs(diffev["optimal_val"] - slsqp["optimal_val"]) < 1e-3
def test_optimizing_coherent_information_with_erasure_channel(): r""" Test optimizing coherent information with an analytic example for erasure channel.""" for err in np.arange(0.01, 1., 0.01): krauss_1 = np.sqrt(1 - err) * np.array([[1., 0.], [0., 1.], [0., 0.]]) krauss_2 = np.sqrt(err) * np.array([[0., 0.], [0., 0.], [0., 1.]]) krauss_3 = np.sqrt(err) * np.array([[0., 0.], [0., 0.], [1., 0.]]) krauss_ops = [krauss_1, krauss_3, krauss_2] channel = AnalyticQChan(krauss_ops, [1, 1], 2, 3) actual = channel.optimize_coherent(n=1, rank=2, param="cholesky", maxiter=50) desired = 1. - err * 2. if err > 0.5: desired = 0. assert np.abs(actual["optimal_val"] - desired) < 1e-5
def test_optimizing_coherent_information_bit_flip_channels(): r"""Test optimizing coherent information with an analytic example for bit-flip channel.""" for err in np.arange(0.01, 1., 0.01): krauss_1 = np.array([[1., 0.], [0., 1]], dtype=np.complex128) * np.sqrt(1 - err) krauss_2 = np.array([[0., 1], [1., 0.]], dtype=np.complex128) * np.sqrt(err) krauss_ops = [krauss_1, krauss_2] channel = AnalyticQChan(krauss_ops, [1, 1], 2, 2) actual = channel.optimize_coherent(n=1, rank=2, param="cholesky", maxiter=50) desired = 1 + np.log2(err) * err + np.log2(1 - err) * (1 - err) print(err, desired, actual["optimal_val"]) assert np.abs(actual["optimal_val"] - desired) < 1e-3
def test_optimizing_coherent_information_erasure_using_choi_matrix(): r"""Test optimizing coherent information with an analytic example for erasure channel.""" for err in np.arange(0.01, 1., 0.01): krauss_1 = np.sqrt(1 - err) * np.array([[1., 0.], [0., 1.], [0., 0.]]) krauss_2 = np.sqrt(err) * np.array([[0., 0.], [0., 0.], [0., 1.]]) krauss_3 = np.sqrt(err) * np.array([[0., 0.], [0., 0.], [1., 0.]]) krauss_ops = [krauss_1, krauss_3, krauss_2] choi = sum([ np.outer(np.ravel(x, order="F"), np.conj(np.ravel(x, order="F"))) for x in krauss_ops ]) channel = AnalyticQChan(choi, numb_qubits=[1, 1], dim_in=2, dim_out=3) actual = channel.optimize_coherent(1, 2, param="cholesky", maxiter=50) desired = 1. - err * 2. if err > 0.5: desired = 0. assert np.abs(actual["optimal_val"] - desired) < 1e-3
def effective_channel_with_stabilizers(stabilizer, code_param, pauli_errors, optimize="coherent", sparse=False, options=None): r""" Calculate the effective channel with respect to a set of pauli-errors and stabilizer elements. Parameters ---------- stabilizer : list List of strings representing stabilizer elements. code_param : tuple A tuple (n, k) where n is the number of encoded qubits and k is the number of logical qubits. pauli_errors : list List of krauss operators as numpy arrays that are scalar multiples of the pauli group and hence represent a Pauli Channel. optimize : str If optimize is "coherent" (default), then it optimizes the coherent information. If optimize is "fidelity", then it optimizes the minimum fidelity. sparse : bool If True, then pauli elements of stabilizer code are sparse. options : None or dict Dictionary of parameters for 'AnalyticQCodes.optimize_coherent' and 'AnalyticQCodes.optimize_fidelity' optimizations procedures. Should have parameters, 'param' : str Parameterization of density matrix, default is 'overparam'. Can also be 'cholesky.' Can also provide own's own parameterization by being a subclass of ParameterizationABC. 'lipschitz': int Integer of number of samplers to be used for lipschitz sampler. Default is 50 'use_pool' : int The number of pool proccesses to be used by the multiprocessor library. Default is 3. 'maxiter' : int Maximum number of iterations. Default is 500. 'samples' : list, optional List of vectors that satisfy the parameterization from "param", that are served as initial guesses for the optimization procedure. Optional, unless 'lipschitz' is zero. Returns ------- dict : The result is a dictionary with fields: optimal_rho : np.ndarray The density matrix of the optimal solution. optimal_val : float The optimal value of either coherent information or fidelity. method : str Either diffev or slsqp. success : bool True if optimizer converges. objective : str Either coherent or fidelity lipschitz : bool True if uses lipschitz properties to find initial guesses. """ if not isinstance(optimize, str): raise TypeError("Optimize should be a string.") if not (optimize == "coherent" or optimize == "fidelity"): raise TypeError("Optimize should either be coherent or fidelity.") if 2**code_param[1] != pauli_errors[0].shape[1]: raise TypeError( "Number of Columns of Pauli error does not match 2**k.") # Parameters for optimization # TODO: add coherent information parameters. # Set up the objects, stabilizer code, pauli-channel error, respectively. stab = StabilizerCode(stabilizer, code_param[0], code_param[1]) # Figure out the dimensions of channel later. error_chan = AnalyticQChan(pauli_errors, [1, 1], 2, 2, sparse=sparse) error_chan.krauss.update_kraus_operators(code_param[0] // code_param[1]) # Get Kraus Operator for encoder. encoder = stab.encode_krauss_operators() # Get the kraus operators for the stabilizers that anti-commute with each kraus operator. kraus = stab.kraus_operators_correcting_errors( error_chan.krauss.nth_kraus_ops, sparse=sparse) # Multiply by the encoder to get the full approximate error-correcting. kraus = [x.dot(encoder) for x in kraus] # Construct new kraus operators. total_chan = AnalyticQChan(kraus, [code_param[1], code_param[0]], 2, 2, sparse=True) # Solve the objective function if optimize == "coherent": result = total_chan.optimize_coherent(n=1, rank=2, optimizer="slsqp", param="overparam", lipschitz=25, use_pool=3, maxiter=250) else: result = total_chan.optimize_fidelity(n=1, optimizer="slsqp", param="overparam", lipschitz=25, use_pool=3, maxiter=250) return result