Source code for entanglish.PureStEnt

from entanglish.EntangCase import *


[docs]class PureStEnt(EntangCase): """ This class is a child of class EntangCase. Its purpose is to calculate the ( bipartite) quantum entanglement E_xy of a pure state ``|psi_xy>`` where x and y constitute a bi-partition of the set of all qudits. E_xy is defined here as the von Neumann entropy S(dm_x) of a density matrix dm_x, where dm_x = trace_y dm_xy, where ``dm_xy = |psi_xy><psi_xy|``. Attributes ---------- den_mat : DenMat """
[docs] def __init__(self, den_mat, approx='eigen', num_bstrap_steps=1, check_purity=True, verbose=False): """ Constructor. If check_purity = True, checks that den_mat is a pure state (has rank 1) Parameters ---------- den_mat : DenMat approx : str num_bstrap_steps : int check_purity : bool verbose : bool Returns ------- """ if check_purity: assert den_mat.is_pure_state(), \ 'the density matrix does not represent a pure state' EntangCase.__init__(self, len(den_mat.row_shape), approx, num_bstrap_steps, verbose) self.den_mat = den_mat
[docs] def get_entang(self, axes_subset): """ This method returns the von Neumann entropy S(dm_x), where dm_x = trace_y dm_xy, where x = axes_subset, and y is the set of all other axes. Parameters ---------- axes_subset : set[int] Returns ------- float """ traced_axes_set = self.den_mat.get_set_of_all_other_axes(axes_subset) partial_dm = self.den_mat.get_partial_tr(traced_axes_set) if self.approx == 'eigen': entang = partial_dm.get_entropy('eigen') elif self.approx == 'pade': entang = partial_dm.get_entropy('pade') elif self.approx == 'pert': if self.num_bstrap_steps == 1: pert = DenMatPertTheory.new_with_separable_dm0(partial_dm, self.verbose) evas = pert.evas_of_dm_to_2nd_order else: evas, evec_cols = \ DenMatPertTheory.do_bstrap_with_separable_dm0( partial_dm, self.num_bstrap_steps, self.verbose) if self.verbose: print('approx evas', np.sort(evas)) print('exact evas', np.linalg.eigvalsh(partial_dm.arr)) evas[evas < 1e-6] = 1e-6 evas /= np.sum(evas) entang = ut.get_entropy_from_probs(evas) else: assert False return entang
if __name__ == "__main__": from entanglish.SymNupState import * def main(): def extra_str(meth, num_steps): return ', ' + str(num_steps) + ' steps' \ if meth == 'pert' else '' num_qbits = 4 num_up = 2 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) print('-------------------dm1') for approx in ['eigen', 'pert']: num_bstrap_steps = 40 print('-----approx=' + approx + extra_str(approx, num_bstrap_steps)) ecase = PureStEnt(dm1, approx, num_bstrap_steps, 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)) dm2 = DenMat(24, (3, 2, 2, 2)) np.random.seed(123) st_vec = ut.random_st_vec(24) dm2.set_arr_from_st_vec(st_vec) print('-------------------dm2') num_bstrap_steps = 40 for approx in ['eigen', 'pert']: print('-----approx=', approx + extra_str(approx, num_bstrap_steps)) ecase = PureStEnt(dm2, approx, num_bstrap_steps, verbose=False) print('entang_023:', ecase.get_entang({0, 2, 3})) print('entang_02:', ecase.get_entang({0, 2})) print('entang_1:', ecase.get_entang({1})) main()