Source code for entanglish.FormationEnt

from entanglish.SquashedEnt import *


[docs]class FormationEnt(SquashedEnt): """ This class is a child of class SquashedEnt. Its purpose is to calculate the (bipartite) quantum entanglement Exy of a mixed state density matrix Dxy with parts x and y. Exy is defined here as the entanglement of formation Exy = sum_alp w_a[alp] min S(Dx_a[alp]) where S(Dx_a[alp]) is the von Neumann entropy for density matrix Dx_a[ alp] = tr_y Dxy_a[alp]. The minimum is over all Dxy_a[alp] such that Dxy_a[alp] is a pure state |psi[alp]><psi[alp]|, and sum_alp w_a[ alp] Dxy_a[ alp] = Dxy where Dxy is a given, fixed density matrix. If we add to the definition of squashed entanglement the further constraint that Dxy_a[alp] is a pure state for all alp, then the squashed entanglement of Dxy becomes precisely the entanglement of formation of Dxy. In this class, most of the steps used for calculating entang of formation are the same as those for calculating squashed entang. Those steps that aren't are turned on or off with the bool flag calc_formation_ent A closed exact formula is known, thanks to Wootters, for the entang of formation of an arbitrary mixture of 2 qubits. Class TwoQubitState of entanglish contains an implementation of said formula. See Ref.1 for a detailed explanation of the algos used in this class. References ---------- 1. R.R. Tucci, "A New Algorithm for Calculating Squashed Entanglement and a Python Implementation Thereof" """
[docs] def __init__(self, *args, **kwargs): """ Constructor Parameters ---------- args : list of args of SquashedEnt constructor kwargs : dictionary of kwargs of SquashedEnt constructor """ SquashedEnt.__init__(self, *args, **kwargs) self.calc_formation_ent = True # much smaller than for squashed entang self.eps_log = 1e-2
if __name__ == "__main__": from entanglish.TwoQubitState import * from entanglish.SymNupState import * def main1(): print('###############################main1, rand, 3 qubits') np.random.seed(123) dm = DenMat(8, (2, 2, 2)) evas_of_dm_list = [ np.array([.07, .03, .25, .15, .3, .1, .06, .04]) , np.array([.05, .05, .2, .2, .3, .1, .06, .04]) ] recursion_init = "eigen+" num_ab_steps = 100 print("recursion_init=", recursion_init) print('num_ab_steps=', num_ab_steps) for evas_of_dm in evas_of_dm_list: evas_of_dm /= np.sum(evas_of_dm) print('***************new dm') print('evas_of_dm\n', evas_of_dm) dm.set_arr_to_rand_den_mat(evas_of_dm) ecase = FormationEnt(dm, num_ab_steps, recursion_init=recursion_init, verbose=True) print('ent_02_1=', ecase.get_entang({0, 2})) def main2(): print('###############################main2, sym nup') num_qbits = 4 num_up = 1 dm1 = DenMat(1 << num_qbits, tuple([2]*num_qbits)) st = SymNupState(num_up, num_qbits) st_vec = st.get_st_vec() dm1.set_arr_from_st_vec(st_vec) recursion_init = "eigen+" num_ab_steps = 15 print("recursion_init=", recursion_init) print('num_ab_steps=', num_ab_steps) ecase = FormationEnt(dm1, num_ab_steps, recursion_init=recursion_init, verbose=False) print('entang_023: algo value, known value\n', ecase.get_entang({0, 2, 3}), st.get_known_entang(3)) print('entang_02: algo value, known value\n', ecase.get_entang({0, 2}), st.get_known_entang(2)) print('entang_1: algo value, known value\n', ecase.get_entang({1}), st.get_known_entang(1)) def main3(): print('###############################main3, werner 2 qubit') dm1 = TwoQubitState.get_bell_basis_diag_dm(.7) recursion_init = "eigen+" num_ab_steps = 50 print("recursion_init=", recursion_init) print('num_ab_steps=', num_ab_steps) for dm in [dm1]: print("-------new dm") formation_entang =\ TwoQubitState.get_known_formation_entang(dm) ecase = FormationEnt(dm, num_ab_steps, recursion_init=recursion_init, verbose=True) print('entang_0: algo value, known value\n', ecase.get_entang({1}), formation_entang) def main4(): print('###############################main4, rand, 2 qubit') np.random.seed(123) dm2 = DenMat(4, (2, 2)) dm2.set_arr_to_rand_den_mat(np.array([.1, .2, .3, .4])) dm3 = DenMat(4, (2, 2)) dm3.set_arr_to_rand_den_mat(np.array([.1, .1, .1, .7])) recursion_init = "eigen+" num_ab_steps = 50 print("recursion_init=", recursion_init) print('num_ab_steps=', num_ab_steps) for dm in [dm2, dm3]: print("-------new dm") formation_entang =\ TwoQubitState.get_known_formation_entang(dm) ecase = FormationEnt(dm, num_ab_steps, recursion_init=recursion_init, verbose=True) print('entang_0: algo value, known value\n', ecase.get_entang({1}), formation_entang) main1() main2() main3() main4()