def main1(): print('--------------------main1') np.random.seed(123) dm = DenMat(8, (2, 2, 2)) exact_evas = np.array([.1, .3, .3, .1, .2, .1, .6, .7]) exact_evas /= np.sum(exact_evas) print('evas of dm\n', np.sort(exact_evas)) dm.set_arr_to_rand_den_mat(exact_evas) pert = DenMatPertTheory.new_with_separable_dm0(dm, verbose=True) # print('evas of dm to 2nd order (after 1 step)\n', # np.sort(pert.evas_of_dm_to_2nd_order), # 'sum=', np.sum(pert.evas_of_dm_to_2nd_order)) # print('evas of dm\n', np.sort(evas)) # print('evas_of_dm0\n', pert.dm0_eigen_sys[0]) # # print('diag of del_dm in sbasis\n', # np.diag(pert.del_dm_in_sbasis.arr.real)) # print('del_dm\n', pert.del_dm) # dm0 = pert.get_dm0() # print('dm0\n', dm0) num_steps = 40 # print('evas_of_dm\n', evas) main_test(dm, exact_evas, pert, num_steps)
def main(): num_qbits = 5 num_up = 2 dm = DenMat(1 << num_qbits, tuple([2]*num_qbits)) st = SymNupState(num_up, num_qbits) st_vec = st.get_st_vec() dm.set_arr_from_st_vec(st_vec) ecase = PureStEnt(dm, 'eigen') pf = ecase.get_entang_profile() # print(',,...', pf) ecase.print_entang_profiles([pf, pf], dm.row_shape)
def main2(): print('--------------------main2') np.random.seed(123) dm1 = DenMat(3, (3,)) evas1 = np.array([.1, .1, .4]) evas1 /= np.sum(evas1) dm1.set_arr_to_rand_den_mat(evas1) # print('dm1\n', dm1) dm2 = DenMat(2, (2,)) evas2 = np.array([.8, .3]) evas2 /= np.sum(evas2) dm2.set_arr_to_rand_den_mat(evas2) # print('dm2\n', dm2) dm = DenMat.get_kron_prod_of_den_mats([dm1, dm2]) const = 0 # const = 1 dm.add_const_to_diag_of_arr(const) dm.normalize_diag_of_arr() print('kron evas\n', np.sort(ut.kron_prod([evas1, evas2]))) exact_evas = np.linalg.eigvalsh(dm.arr) print('evas_of_dm\n', exact_evas) pert = DenMatPertTheory.new_with_separable_dm0(dm, verbose=True) # print('evas of dm to 2nd order (after 1 step)\n', # np.sort(pert.evas_of_dm_to_2nd_order), # 'sum=', np.sum(pert.evas_of_dm_to_2nd_order)) num_steps = 10 main_test(dm, exact_evas, pert, num_steps)
def main3(): print('--------------------main3') num_qbits = 4 num_up = 2 dm = DenMat(1 << num_qbits, tuple([2]*num_qbits)) st = SymNupState(num_up, num_qbits) st_vec = st.get_st_vec() dm.set_arr_from_st_vec(st_vec) # dm.depurify(.1) exact_evas = np.linalg.eigvalsh(dm.arr) print('evas_of_dm\n', exact_evas, 'sum=', np.sum(exact_evas)) pert = DenMatPertTheory.new_with_separable_dm0(dm, verbose=True) num_steps = 80 main_test(dm, exact_evas, pert, num_steps)
def do_bstrap_with_separable_dm0(dm, num_steps=1, verbose=False): """ This method returns the same thing as the method (found in its parent class) DenMatPertTheory.do_bstrap( ). However, their names differ by a '_with_separable_dm0' at the end and their inputs are different. This one takes as input a density matrix dm and calculates dm0_eigen_sys and del_dm from that, assuming that dm0 is the Kronecker product of the marginals of dm. Parameters ---------- dm : DenMat num_steps : int verbose : bool Returns ------- tuple[np.ndaray, np.ndarray] """ if dm.marginals is None: dm.set_marginals() esys = dm.get_eigen_sys_of_marginals() dm0_eigen_sys = (ut.kron_prod(esys[0]), ut.kron_prod(esys[1])) arr = ut.kron_prod([marg.arr for marg in dm.marginals]) dm0 = DenMat(dm.num_rows, dm.row_shape, arr) return DenMatPertTheory.do_bstrap( dm0_eigen_sys, dm-dm0, num_steps, verbose)
def get_den_mat_with_bound_entang(p): """ This method returns a DenMat with num_rows = 8 and row_shape = (2, 4) that is known to have bound entanglement. https://arxiv.org/abs/quant-ph/9703004 Parameters ---------- p : float a probability, 0 < p < 1 Returns ------- DenMat """ num_rows = 8 row_shape = (2, 4) a = (1 + p) / 2 b = np.sqrt(1 - p**2) / 2 arr1 = np.array([[p, 0, 0, 0, 0, p, 0, 0], [0, p, 0, 0, 0, 0, p, 0], [0, 0, p, 0, 0, 0, 0, p], [0, 0, 0, p, 0, 0, 0, 0], [0, 0, 0, 0, a, 0, 0, b], [p, 0, 0, 0, 0, p, 0, 0], [0, p, 0, 0, 0, 0, p, 0], [0, 0, p, 0, b, 0, 0, a]]) return DenMat(num_rows, row_shape, arr1 / np.trace(arr1))
def get_bell_basis_diag_dm(fid, prob_dict=None): """ This method returns a DenMat which is constructed as a linear combination, with coefficients prob_dict, of the Bell basis state projection operators. So the den matrix returned is diagonal in the Bell basis. If prob_dict is not None, use it and ignore value of fid. If prob_dict is None, use prob_dict for an "isotropic" Werner state with fidelity fid. That is, prob_dict[ "==+"]=fid, prob_dict[x]=( 1-fid)/3 for all x other than '==+" Parameters ---------- fid : float fidelity. prob_dict : dict[str, float]|None Returns ------- DenMat """ if prob_dict: assert ut.is_prob_dist(np.array(list(prob_dict.values()))) assert set(prob_dict.keys()) == TwoQubitState.bell_key_set() else: assert 0 <= fid <= 1 prob_dict = {} for key in TwoQubitState.bell_key_set(): if key == '==+': prob_dict[key] = fid else: prob_dict[key] = (1 - fid) / 3 dm = DenMat(4, (2, 2)) dm.set_arr_to_zero() for key in prob_dict.keys(): st_vec = TwoQubitState.get_bell_basis_st_vec(key) dm.arr += np.outer(st_vec, np.conj(st_vec)) * prob_dict[key] return dm
def main(): print('4 Bell Basis states**********************') for bits_are_equal in [True, False]: for mid_sign in ['+', '-']: st_vec = OtherStates.get_bell_basis_st_vec(bits_are_equal, mid_sign) dm = DenMat(4, (2, 2)) dm.set_arr_from_st_vec(st_vec) ecase = PureStEnt(dm) pf = ecase.get_entang_profile() print('----------bits_are_equal=', bits_are_equal, ', mid_sign=', mid_sign) print("st_vec=\n", st_vec) ecase.print_entang_profiles([pf], dm.row_shape) print('bound entang state **********************') dm_bd = OtherStates.get_den_mat_with_bound_entang(.5) num_hidden_states = 5 num_ab_steps = 30 ecase = SquashedEnt(dm_bd, num_hidden_states, num_ab_steps, verbose=True) pf = ecase.get_entang_profile() ecase.print_entang_profiles([pf], dm_bd.row_shape)
def check_max_entang_st(st): """ This method checks that the object st of class MaxEntangState does indeed carry maximal entanglement. The entanglement is calculated 3 different ways (von Neumann entropy of 2 partial traces of density matrix, and from known value) and the 3 values are checked to agree. Parameters ---------- st : MaxEntangState Returns ------- None """ dm = DenMat(st.num_rows, st.row_shape) st_vec = st.get_st_vec() dm.set_arr_from_st_vec(st_vec) ent1 = dm.get_partial_tr(set(st.y_axes)).get_entropy() ent2 = dm.get_partial_tr(set(st.x_axes)).get_entropy() ent3 = np.log(st.num_vals_min) assert abs(ent1 - ent2) < 1e-6 and abs(ent1 - ent3) < 1e-6, \ str(ent1) + ', ' + str(ent2) + ', ' + str(ent3)
def get_dm0(self): """ This method returns the unperturbed density matrix dm0. We define this method so as to avoid storing dm0. Returns ------- DenMat """ evas = self.dm0_eigen_sys[0] evec_cols = self.dm0_eigen_sys[1] arr = ut.fun_of_herm_arr_from_eigen_sys(lambda x: x, evas, evec_cols) num_rows = self.del_dm.num_rows row_shape = self.del_dm.row_shape return DenMat(num_rows, row_shape, arr)
def get_time_reversed_dm(dm): """ This method returns a DenMat which is the time reversed version of a DenMat dm for 2 qubits. Parameters ---------- dm : DenMat Returns ------- DenMat """ assert dm.num_rows == 4 sigy = np.array([[0, -1j], [1j, 0]]) dm_sigyy = DenMat(4, (2, 2), arr=ut.kron_prod([sigy, sigy])) return dm_sigyy * dm.conj() * dm_sigyy
def new_with_separable_dm0(dm, verbose=False): """ This method returns a DenMatPertTheory built from a density matrix dm, assuming that dm0 is the Kronecker product of the marginals of dm. Parameters ---------- dm : DenMat verbose : bool Returns ------- DenMatPertTheory """ if dm.marginals is None: dm.set_marginals() esys = dm.get_eigen_sys_of_marginals() dm0_eigen_sys = (ut.kron_prod(esys[0]), ut.kron_prod(esys[1])) arr = ut.kron_prod([marg.arr for marg in dm.marginals]) dm0 = DenMat(dm.num_rows, dm.row_shape, arr) return DenMatPertTheory(dm0_eigen_sys, dm - dm0, verbose)
def main1(): print('4 Bell Basis states**********************') for key in TwoQubitState.bell_key_set(): st_vec = TwoQubitState.get_bell_basis_st_vec(key) dm = DenMat(4, (2, 2)) dm.set_arr_from_st_vec(st_vec) ecase = PureStEnt(dm) pf = ecase.get_entang_profile() print('----------key:', key) print("st_vec=\n", st_vec) ecase.print_entang_profiles([pf], dm.row_shape) print("*******************************") dm1 = TwoQubitState.get_bell_basis_diag_dm(fid=.7) # print('arr=\n', dm1.arr) 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])) for dm in [dm1, dm2, dm3]: print("----------new dm") print("formation_entang=", TwoQubitState.get_known_formation_entang(dm))