Ejemplo n.º 1
0
def entropy_half_chain_split(state, base, N, basis_A_refs, basis_B_refs):
    #generate coefficient matrix
    N_A = int(np.floor(N / 2))
    N_B = int(N - np.floor(N / 2))

    basis_A_refs_unique = np.unique(basis_A_refs)
    basis_B_refs_unique = np.unique(basis_B_refs)

    # M=np.zeros((np.power(base,N_A),np.power(base,N_B)),dtype=complex)
    M = np.zeros((np.size(basis_A_refs_unique), np.size(basis_B_refs_unique)),
                 dtype=complex)

    #coefficients of state form matrix M_ij*state^A_i*state^V_j
    for n in range(0, np.size(state, axis=0)):
        if np.abs(state[n]) > 1e-4:
            i, j = int(basis_A_refs[n]), int(basis_B_refs[n])
            i_index, j_index = find_index_bisection(
                i, basis_A_refs_unique), find_index_bisection(
                    j, basis_B_refs_unique)
            M[i_index, j_index] = M[i_index, j_index] + state[n]
    # print("M generated")

    #schmidt decomposition
    U, S, V = np.linalg.svd(M)
    to_del = []
    for n in range(0, np.size(S, axis=0)):
        if S[n] == 0:
            to_del = np.append(to_del, n)
    for n in range(np.size(to_del, axis=0) - 1, -1, -1):
        S = np.delete(S, to_del[n])
    # print("SVD Done")

    #von-neuman entropy
    entropy = -np.vdot(np.abs(S)**2, np.log(np.abs(S)**2))
    return entropy
Ejemplo n.º 2
0
def energy_basis(state, H):
    #find sym blocks state has non zero overlap in
    state_ref = bin_to_int_base_m(state, H.system.base)
    state_index = find_index_bisection(state_ref, H.system.basis_refs)
    sym_ref = H.syms.sym_data[state_index, 0]
    k_refs = H.syms.find_k_ref(sym_ref)

    #dict to store state in sym sector basis
    z_sym = dict()
    eigenvalues = dict()
    for n in range(0, np.size(k_refs, axis=0)):
        psi = ref_state(state_ref, H.system)
        z_sym[n] = psi.sym_basis(k_refs[n], H.syms)
        eigenvalues[n] = H.sector.eigvalues(k_refs[n])

    #dict to store state from sym sector in energy eigenbasis
    z_energy = dict()
    for n in range(0, np.size(k_refs, axis=0)):
        z_energy[n] = np.zeros(np.size(H.sector.eigvalues(k_refs[n])),
                               dtype=complex)
        #find coefficients by taking overlaps
        for m in range(0, np.size(z_energy[n], axis=0)):
            z_energy[n][m] = np.vdot(
                H.sector.eigvectors(k_refs[n])[:, m], z_sym[n])

    #combine all sym sectors
    z_init = z_energy[0]
    eig_f = eigenvalues[0]
    for n in range(1, len(z_energy)):
        z_init = np.append(z_init, z_energy[n])
        eig_f = np.append(eig_f, eigenvalues[n])
    return z_init, eig_f
Ejemplo n.º 3
0
    def bulk_eval(state, t, H, use_syms=None):
        if use_syms == None:
            z_ref = bin_to_int_base_m(state, H.system.base)
            z_index = find_index_bisection(z_ref, H.system.basis_refs)
            z_init = H.sector.eigvectors()[z_index, :]
            eig_f = H.sector.eigvalues()
        else:
            z_init, eig_f = energy_basis(state, H)

        fidelity_y = np.zeros(np.size(t))
        for n in range(0, np.size(t, axis=0)):
            evolved_state = time_evolve_state(z_init, eig_f, t[n])
            fidelity_y[n] = np.abs(np.vdot(evolved_state, z_init))**2
        return fidelity_y
Ejemplo n.º 4
0
    def eval(state, t, H, use_syms=None):
        if use_syms == None:
            z_ref = bin_to_int_base_m(state, H.system.base)
            z_index = find_index_bisection(z_ref, H.system.basis_refs)
            z_init = H.sector.eigvectors()[z_index, :]
            eig_f = H.sector.eigvalues()
        else:
            z_init, eig_f = energy_basis(state, H)

        evolved_state = time_evolve_state(z_init, eig_f, t)
        print(np.abs(np.vdot(z_init, evolved_state))**2)
        # if t<0.5:
        # return -100
        # else:
        return np.abs(np.vdot(z_init, evolved_state))**2
Ejemplo n.º 5
0
def fidelity_erorr(coef):
    coef = coef[0]
    Ip_total = H_operations.add(Ip, Ip_pert, np.array([1, coef]))
    Im_total = H_operations.add(Im, Im_pert, np.array([1, coef]))
    Kp_total = H_operations.add(Kp, Kp_pert, np.array([1, coef]))
    Km_total = H_operations.add(Km, Km_pert, np.array([1, coef]))
    Lp_total = H_operations.add(Lp, Lp_pert, np.array([1, coef]))
    Lm_total = H_operations.add(Lm, Lm_pert, np.array([1, coef]))

    H = H_operations.add(Ip_total, Im_total, np.array([1j, -1j]))
    H = H_operations.add(H, Kp_total, np.array([1, -1j]))
    H = H_operations.add(H, Km_total, np.array([1, 1j]))
    H = H_operations.add(H, Lp_total, np.array([1, 1j]))
    H = H_operations.add(H, Lm_total, np.array([1, -1j]))

    H.sector.find_eig(k)

    z = zm_state(2, 1, pxp, 1)
    block_refs = pxp_syms.find_block_refs(k)
    psi = np.zeros(np.size(block_refs))
    loc = find_index_bisection(z.ref, block_refs)
    psi[loc] = 1
    psi_energy = np.dot(np.conj(np.transpose(H.sector.eigvectors(k))), psi)

    t = np.arange(0, 20, 0.01)
    f = np.zeros(np.size(t))
    for n in range(0, np.size(t, axis=0)):
        evolved_state = time_evolve_state(psi_energy, H.sector.eigvalues(k),
                                          t[n])
        f[n] = np.abs(np.vdot(evolved_state, psi_energy))**2
    for n in range(0, np.size(f, axis=0)):
        if f[n] < 0.1:
            cut = n
            break
    f0 = np.max(f[cut:])
    plt.scatter(H.sector.eigvalues(k), np.log10(np.abs(psi_energy)**2))
    plt.title(r"$PCP+\lambda(PPCP+PCPP), N=$" + str(pxp.N))
    plt.xlabel(r"$E$")
    plt.ylabel(r"$\log(\vert \langle \psi \vert E \rangle \vert^2)$")
    plt.show()
    plt.plot(t, f)
    plt.title(r"$PCP+\lambda(PPCP+PCPP), N=$" + str(pxp.N))
    plt.xlabel(r"$t$")
    plt.ylabel(r"$\vert \langle \psi(0) \vert \psi(t) \rangle \vert^2$")
    plt.show()
    return 1 - f0
Ejemplo n.º 6
0
    def bulk_eval(state, H, k_vec=None):
        if k_vec is None:  #no symmetry, use full basis
            z_ref = bin_to_int_base_m(state, H.system.base)
            z_index = find_index_bisection(z_ref, H.system.basis_refs)
            z_energy = H.sector.eigvectors()[z_index, :]
            eigenvalues = H.sector.eigvalues()
        else:  #symmetry used, just plot the given sym_block
            z_ref = bin_to_int_base_m(state, H.system.base)
            psi = ref_state(z_ref, H.system)
            z_mom = psi.sym_basis(k_vec, H.syms)
            # z_mom = z_mom * np.power(np.vdot(z_mom,z_mom),-0.5)
            z_energy = np.zeros(np.size(H.sector.eigvalues(k_vec)),
                                dtype=complex)
            for n in range(0, np.size(z_energy, axis=0)):
                z_energy[n] = np.vdot(z_mom, H.sector.eigvectors(k_vec)[:, n])
            eigenvalues = H.sector.eigvalues(k_vec)

        overlap = np.log10(np.abs(z_energy)**2)
        return overlap
Ejemplo n.º 7
0
    def plot(state, t, H, use_syms=None):
        print("Plotting Fidelity...")
        if use_syms == None:
            z_ref = bin_to_int_base_m(state, H.system.base)
            z_index = find_index_bisection(z_ref, H.system.basis_refs)
            z_init = H.sector.eigvectors()[z_index, :]
            eig_f = H.sector.eigvalues()
        else:
            z_init, eig_f = energy_basis(state, H)

        fidelity_y = np.zeros(np.size(t))
        for n in range(0, np.size(t, axis=0)):
            evolved_state = time_evolve_state(z_init, eig_f, t[n])
            fidelity_y[n] = np.abs(np.vdot(evolved_state, z_init))**2

        plt.xlabel("t")
        plt.ylabel(r"$\vert \langle \psi(t) \vert \psi(0) \rangle \vert^2$")
        plt.title(str(H.system.base) + " Colour, N=" + str(H.system.N))
        plt.plot(t, fidelity_y)
    def sym_basis(self,k_vec,sym_data):
        #permutations of all array indices for d dimensional arrayk, d=no syms
        #for looping through d-dim array
        orbit_indices = list(nd_range(0,self.system.N,np.size(sym_data.syms)))

        #lowest symmetry equiv state, the reference
        # index = self.system.keys[self.ref]
        sym_ref = sym_data.sym_data[self.system.keys[self.ref],0]
        L = sym_data.sym_data[self.system.keys[self.ref],2:]
        allowed_mom = np.zeros(np.size(k_vec))

        periods = np.zeros(np.size(sym_data.syms))
        for k in range(0,np.size(sym_data.syms,axis=0)):
            temp_orbit = sym_data.syms[k].create_orbit(sym_ref)
            periods[k] = np.size(temp_orbit)

        psi = sym_state(self.ref,k_vec,sym_data,self.system)
        temp = psi.prod_basis()

        orbit_size = 0
        orbit_ref_indices = []
        for n in range(0,np.size(temp,axis=0)):
            if np.abs(temp[n]) > 1e-5:
                orbit_size = orbit_size + 1
                orbit_ref_indices = np.append(orbit_ref_indices,n)

        U = np.zeros(orbit_size,dtype=complex)

        k_refs = sym_data.find_k_ref(sym_ref)
            
        #loop through all sym sectors and keep |a_ref,k1,...kn>=c_n|n> to form U
        c,d  = 0,0
        for m in range(0,np.size(k_refs,axis=0)):
            psi = sym_state(self.ref,k_refs[m],sym_data,self.system)
            temp = psi.prod_basis()
            U_temp = np.zeros(orbit_size,dtype=complex)
            for k in range(0,np.size(orbit_ref_indices,axis=0)):
                U_temp[k] = temp[int(orbit_ref_indices[k])]
            U = np.vstack((U,U_temp))

        not_found = 1
        for n in range(0,np.size(k_refs,axis=0)):
            if (k_refs[n] == k_vec).all() == True:
                j_index = n
                not_found = 0
                break
        if not_found == 1:
            print("Error: State not in this symmetry sector")
        else:
            U = np.delete(U,0,axis=0)

            #find column index of relevant state
            for n in range(0,np.size(orbit_ref_indices,axis=0)):
                if orbit_ref_indices[n] == self.key:
                    i_index = n

            #delete equivalent rows
            eq_ind=np.arange(0,np.size(k_refs,axis=0)) #track what quant sectors are equiv
            for n in range(0,np.size(U,axis=0)):
                to_del = []
                for m in range(n+1,np.size(U,axis=0)):
                    if (np.abs(U[m]-U[n])<1e-5).all() == True:
                        to_del = np.append(to_del,m)
                        eq_ind[m] = n
                    elif (np.abs(1j * U[m]-U[n])<1e-5).all() == True:
                        to_del = np.append(to_del,m)
                        eq_ind[m] = n
                    elif (np.abs(-1j * U[m]-U[n])<1e-5).all() == True:
                        to_del = np.append(to_del,m)
                        eq_ind[m] = n
                    elif (np.abs(-1 * U[m]-U[n])<1e-5).all() == True:
                        to_del = np.append(to_del,m)
                        eq_ind[m] = n
                for m in range(np.size(to_del,axis=0)-1,-1,-1):
                    U = np.delete(U,to_del[m],axis=0)

            #update j_index, deleted eq rows
            j_index = eq_ind[j_index]
            found=[]
            keys=dict()
            c = 0
            for n in range(0,np.size(eq_ind,axis=0)):
                if eq_ind[n] not in found:
                    keys[eq_ind[n]]=c
                    c = c+1
                    found = np.append(found,eq_ind[n])
            j_index = keys[j_index]

            #inv transformation
            U_inv = np.linalg.inv(U)
            coef = U_inv[i_index,j_index]

            block_references = sym_data.find_block_refs(k_vec)
            prod_state = np.zeros(np.size(block_references),dtype=complex)
            # ref_index = self.system.keys[sym_ref]
            ref_index = find_index_bisection(sym_ref,block_references)
            prod_state[ref_index] = coef
            return prod_state
 def prod_basis(self):
     v = np.zeros(np.size(self.system.basis_refs))
     index = find_index_bisection(self.ref,self.system.basis_refs)
     v[index] = 1
     return v
Ejemplo n.º 10
0
    def plot(state, H, k_vec=None, label=None):
        print("Plotting eigenstate overlap with given state...")
        if k_vec is None:  #no symmetry, use full basis
            z_ref = bin_to_int_base_m(state, H.system.base)
            z_index = find_index_bisection(z_ref, H.system.basis_refs)
            z_energy = H.sector.eigvectors()[z_index, :]
            eigenvalues = H.sector.eigvalues()
        else:  #symmetry used, just plot the given sym_block
            z_ref = bin_to_int_base_m(state, H.system.base)
            psi = ref_state(z_ref, H.system)
            z_mom = psi.sym_basis(k_vec, H.syms)
            # z_mom = z_mom * np.power(np.vdot(z_mom,z_mom),-0.5)
            z_energy = np.zeros(np.size(H.sector.eigvalues(k_vec)),
                                dtype=complex)
            for n in range(0, np.size(z_energy, axis=0)):
                z_energy[n] = np.vdot(z_mom, H.sector.eigvectors(k_vec)[:, n])
            eigenvalues = H.sector.eigvalues(k_vec)

        overlap = np.log10(np.abs(z_energy)**2)
        to_del = []
        for n in range(0, np.size(overlap, axis=0)):
            if overlap[n] < -10:
                to_del = np.append(to_del, n)
        for n in range(np.size(to_del, axis=0) - 1, -1, -1):
            overlap = np.delete(overlap, to_del[n])
            eigenvalues = np.delete(eigenvalues, to_del[n])

        if label is not None:
            fig = plt.figure()
            ax = fig.add_subplot(111)

        if k_vec is None:
            # plt.scatter(eigenvalues,overlap,alpha=0.6)
            from scipy.stats import gaussian_kde
            x = eigenvalues
            y = overlap
            plt.scatter(x, y)

            # Calculate the point density
            # xy = np.vstack([x,y])
            # z = gaussian_kde(xy)(xy)

            # # Sort the points by density, so that the densest points are plotted last
            # idx = z.argsort()
            # x, y, z = x[idx], y[idx], z[idx]

            # fig, ax = plt.subplots()
            # ax.scatter(x, y, c=z, s=50, edgecolor='')
        else:
            # plt.scatter(eigenvalues,overlap,label=str(k_vec)+r" $\pi /$"+str(H.system.N)+" Symmetry sector")
            plt.scatter(eigenvalues, overlap, color='blue')

        if label is not None:
            A = eigenvalues
            B = overlap
            for i, j in zip(A, B):
                # ax.annotate('%s)' %j, xy=(i,j), xytext=(30,0), textcoords='offset points')
                ax.annotate('(%s,' % i, xy=(i, j))

        plt.legend()
        plt.xlabel("E")
        plt.ylabel(r"$\vert \langle \psi_E \vert \psi \rangle \vert^2$")
        plt.title(str(H.system.base) + " Colour, N=" + str(H.system.N))
        plt.legend()
for n in range(0,np.size(basis_refs,axis=0)):
    perm_basis = np.vstack((perm_basis,perm_basis_states[basis_refs[n]]))
perm_basis = np.transpose(np.delete(perm_basis,0,axis=0))
perm_dim = np.size(perm_basis,axis=1)


H = spin_Hamiltonian(pxp,"x",pxp_syms)
H.gen()
H.sector.find_eig()

H_perm = np.dot(np.conj(np.transpose(perm_basis)),np.dot(H.sector.matrix(),perm_basis))
e,u = np.linalg.eigh(H_perm)

#time evolve state in perm basis,
z_ref = perm_keys(int(N/2),0,N)
z_index = find_index_bisection(z_ref,basis_refs)
psi_energy = np.conj(u[z_index,:])

t=np.arange(0,10,0.1)
evolved_states = np.zeros((pxp.dim,np.size(t)),dtype=complex)
for n in range(0,np.size(t,axis=0)):
    evolved_state_perm_energy = time_evolve_state(psi_energy,e,t[n])
    evolved_state_perm = np.dot(u,evolved_state_perm_energy)
    evolved_state_prod = np.dot(perm_basis,evolved_state_perm)
    evolved_states[:,n] = evolved_state_prod

#minimize distance of evolved states with tensor tree ansatz
def TT_wf(theta1,phi1,theta2,phi2):
    c1_up = 1j * np.exp(-1j * phi1)*np.tan(theta2)
    c1_down = np.cos(theta1)
Ejemplo n.º 12
0
def comP(A, B, relation_object):
    #array with unit cell of A/B indices (eg 2n+1,2n+2,2n+3->1,2,3)
    A_loc = np.arange(A.loc, A.loc + A.length)
    B_loc = np.arange(B.loc, B.loc + B.length)

    #find n_vals=[...] such that end of B string touch A string
    #RHS indices = B.period*n+B.loc
    max_found = 0
    counter = 0
    while max_found == 0:
        #B.period*n+B.loc = (last A site) - counter
        n_max = (A_loc[np.size(A_loc) - 1] - B.loc - counter) / B.period
        if n_max.is_integer() == True:
            max_found = 1
            break
        else:
            counter += 1
    min_found = 0
    counter = 0
    while min_found == 0:
        #B.period*n+(last B site) = (first A site) + counter
        n_min = (A.loc - B_loc[np.size(B_loc) - 1] + counter) / B.period
        if n_min.is_integer() == True:
            min_found = 1
            break
        else:
            counter += 1
    n_vals = np.arange(n_min, n_max + 1)

    #find all overlapping RH terms, store loc in 2d array
    rhs_loc = np.zeros((np.size(n_vals), B.length))
    for n in range(0, np.size(n_vals, axis=0)):
        rhs_loc[n] = np.arange(B.period * n_vals[n] + B.loc,
                               B.period * n_vals[n] + B.loc + B.length)

    #for each rhs loc form "sandwich" of overlapping sites,store each term in nested dictionary
    #eg strings like "P(+P)(-P)P = P+-P"
    rhs_commutes = dict()
    new_coef = np.zeros(np.size(n_vals))
    for n in range(0, np.size(rhs_loc, axis=0)):
        min_loc = int(np.min(np.append(A_loc, rhs_loc[n])))
        max_loc = int(np.max(np.append(A_loc, rhs_loc[n])))

        rhs_commutes[n] = dict()
        for m in range(min_loc, max_loc + 1):
            temp = ''
            if m in rhs_loc[n] and m in A_loc:
                A_loc_index = find_index_bisection(m, A_loc)
                rhs_index = find_index_bisection(m, rhs_loc[n])
                temp += A.string[A_loc_index]
                temp += B.string[rhs_index]
                rhs_commutes[n][m] = temp
            elif m in rhs_loc[n]:
                rhs_index = find_index_bisection(m, rhs_loc[n])
                temp = B.string[rhs_index]
                rhs_commutes[n][m] = temp
            else:
                A_loc_index = find_index_bisection(m, A_loc)
                temp = A.string[A_loc_index]
                rhs_commutes[n][m] = temp
        new_coef[n] = A.coef * B.coef

    #replace known products from relation class
    simplified_commutes = commuted_string_seq()
    for n in range(0, np.size(rhs_loc, axis=0)):
        #identify all pairs of producted operators
        keys = list(rhs_commutes[n])
        paired_keys = []
        for m in range(0, np.size(keys, axis=0)):
            if len(rhs_commutes[n][keys[m]]) > 1:
                paired_keys = np.append(paired_keys, keys[m])

        #replace any PP pairs with P
        for m in range(0, np.size(paired_keys, axis=0)):
            if rhs_commutes[n][paired_keys[m]] == "PP":
                rhs_commutes[n][paired_keys[m]] = "P"
        #replace any QQ pairs with Q
        for m in range(0, np.size(paired_keys, axis=0)):
            if rhs_commutes[n][paired_keys[m]] == "QQ":
                rhs_commutes[n][paired_keys[m]] = "Q"

        #identify remaining pairs
        paired_keys = []
        for m in range(0, np.size(keys, axis=0)):
            if len(rhs_commutes[n][keys[m]]) > 1:
                paired_keys = np.append(paired_keys, keys[m])

        #if no. paired keys == 1 can do regular commutator
        if np.size(paired_keys) == 1:
            #desired syntax
            # simplified_commutators= relations.commutator(rhs_commutes[n][paired_keys[0]])
            simplified_commutators = relation_object.commutator(
                rhs_commutes[n][paired_keys[0]])
            for u in range(0, simplified_commutators.length):
                temp_string_dict = deepcopy(rhs_commutes[n])
                temp_string_dict[
                    paired_keys[0]] = simplified_commutators.entry[u].string

                temp_coef = new_coef[n] * simplified_commutators.entry[u].coef
                simplified_commutes.update(temp_string_dict, temp_coef)
        else:
            AB_coef_orig = np.copy(new_coef[n])
            BA_coef_orig = np.copy(new_coef[n])

            simplified_products_AB = dict()
            simplified_products_BA = dict()
            for m in range(0, np.size(paired_keys, axis=0)):
                simplified_products_AB[m] = relation_object.product(
                    rhs_commutes[n][paired_keys[m]])
                simplified_products_BA[m] = relation_object.product(
                    rhs_commutes[n][paired_keys[m]][::-1])

            index_array_AB = []
            for m in range(0, len(simplified_products_AB)):
                temp = list(simplified_products_AB[m].entry.keys())
                index_array_AB.append(temp)
            from itertools import product
            indices_AB = np.array(list(product(*index_array_AB)))

            index_array_BA = []
            for m in range(0, len(simplified_products_BA)):
                temp = list(simplified_products_BA[m].entry.keys())
                index_array_BA.append(temp)
            from itertools import product
            indices_BA = np.array(list(product(*index_array_BA)))

            if np.size(indices_AB) > 0:
                for u in range(0, np.size(indices_AB, axis=0)):
                    temp_string_dict = deepcopy(rhs_commutes[n])
                    paired_key_index = 0
                    temp_coef = AB_coef_orig
                    for v in range(0, np.size(indices_AB[u], axis=0)):
                        temp_string_dict[paired_keys[
                            paired_key_index]] = simplified_products_AB[
                                v].entry[indices_AB[u][v]].string
                        temp_coef = temp_coef * simplified_products_AB[
                            v].entry[indices_AB[u][v]].coef
                        paired_key_index += 1
                    simplified_commutes.update(temp_string_dict, temp_coef)

            if np.size(indices_BA) > 0:
                for u in range(0, np.size(indices_BA, axis=0)):
                    temp_string_dict = deepcopy(rhs_commutes[n])
                    paired_key_index = 0
                    temp_coef = BA_coef_orig
                    for v in range(0, np.size(indices_BA[u], axis=0)):
                        temp_string_dict[paired_keys[
                            paired_key_index]] = simplified_products_BA[
                                v].entry[indices_BA[u][v]].string
                        temp_coef = temp_coef * simplified_products_BA[
                            v].entry[indices_BA[u][v]].coef
                        paired_key_index += 1
                    simplified_commutes.update(temp_string_dict, -temp_coef)

    rhs_strings = dict()
    new_loc = []
    new_coef_trimmed = []
    c = 0
    for n in range(0, simplified_commutes.no_terms):
        if np.abs(simplified_commutes.terms[n].coef) > 1e-5:
            rhs_strings[c] = simplified_commutes.terms[n].string
            new_loc = np.append(new_loc, simplified_commutes.terms[n].loc)
            new_coef_trimmed = np.append(new_coef_trimmed,
                                         simplified_commutes.terms[n].coef)
            c += 1

    #keep non zero terms
    keys = list(rhs_strings.keys())
    non_zero_strings = dict()
    non_zero_coef = dict()
    non_zero_loc = []
    c = 0
    string_seq = dict()
    for n in range(0, np.size(keys, axis=0)):
        if np.abs(new_coef_trimmed[keys[n]]) > 1e-5:
            string_seq[c] = op_string(new_coef_trimmed[keys[n]],
                                      rhs_strings[keys[n]], A.period,
                                      new_loc[n] % A.period)
            c += 1

    #multiply out variables and orders (all terms will have same variables)
    new_variables, new_orders = A.multiply_variables(B)
    for n in range(0, len(string_seq)):
        string_seq[n].variables = new_variables
        string_seq[n].variable_orders = new_orders
        string_seq[n].update_hash()
    return op_string_seq(string_seq)
def fidelity_erorr(coef,plot=False):
    c=0
    Ip_total = deepcopy(Ip[0])
    for n in range(1,len(Ip)):
        Ip_total = H_operations.add(Ip_total,Ip[n],np.array([1,coef[c+n-1]]))
    Im_total = deepcopy(Im[0])
    for n in range(1,len(Im)):
        Im_total = H_operations.add(Im_total,Im[n],np.array([1,coef[c+n-1]]))
    c += len(Ip)-1
    Kp_total = deepcopy(Kp[0])
    for n in range(1,len(Kp)):
        Kp_total = H_operations.add(Kp_total,Kp[n],np.array([1,coef[c+n-1]]))
    Km_total = deepcopy(Km[0])
    for n in range(1,len(Km)):
        Km_total = H_operations.add(Km_total,Km[n],np.array([1,coef[c+n-1]]))
    c += len(Kp)-1
    Lp_total = deepcopy(Lp[0])
    for n in range(1,len(Lp)):
        Lp_total = H_operations.add(Lp_total,Lp[n],np.array([1,coef[c+n-1]]))
    Lm_total = deepcopy(Lm[0])
    for n in range(1,len(Lm)):
        Lm_total = H_operations.add(Lm_total,Lm[n],np.array([1,coef[c+n-1]]))

    H=H_operations.add(Ip_total,Im_total,np.array([1j,-1j]))
    H=H_operations.add(H,Kp_total,np.array([1,-1j]))
    H=H_operations.add(H,Km_total,np.array([1,1j]))
    H=H_operations.add(H,Lp_total,np.array([1,1j]))
    H=H_operations.add(H,Lm_total,np.array([1,-1j]))

    H.sector.find_eig(k)

    z=zm_state(2,1,pxp,1)
    block_refs = pxp_syms.find_block_refs(k)
    psi = np.zeros(np.size(block_refs))
    loc = find_index_bisection(z.ref,block_refs)
    psi[loc] = 1
    psi_energy = np.dot(np.conj(np.transpose(H.sector.eigvectors(k))),psi)

    t=np.arange(0,20,0.01)
    f=np.zeros(np.size(t))
    for n in range(0,np.size(t,axis=0)):
        evolved_state = time_evolve_state(psi_energy,H.sector.eigvalues(k),t[n])
        f[n] = np.abs(np.vdot(evolved_state,psi_energy))**2
    for n in range(0,np.size(f,axis=0)):
        if f[n] < 0.1:
            cut = n
            break
    f0 = np.max(f[cut:])
    if plot is True:
        plt.scatter(H.sector.eigvalues(k),np.log10(np.abs(psi_energy)**2))
        plt.title(r"$PCP+\lambda(PPCP+PCPP), N=$"+str(pxp.N))
        plt.xlabel(r"$E$")
        plt.ylabel(r"$\log(\vert \langle \psi \vert E \rangle \vert^2)$")
        plt.show()
        plt.plot(t,f)
        plt.title(r"$PCP+\lambda(PPCP+PCPP), N=$"+str(pxp.N))
        plt.xlabel(r"$t$")
        plt.ylabel(r"$\vert \langle \psi(0) \vert \psi(t) \rangle \vert^2$")
        plt.show()
    print(coef,f0)
    return 1-f0
Hp[2].site_ops[1] = np.array([[0, 0], [1, 0]])
Hp[2].site_ops[2] = np.array([[0, 1], [0, 0]])
Hp[2].site_ops[3] = np.array([[-1, 0], [0, 1]])
Hp[2].site_ops[4] = np.array([[0, 0], [0, 1]])
Hp[2].model = np.array([[1, 3, 3, 2], [2, 3, 3, 1]])
Hp[2].model_coef = np.array([1, 1])
Hp[2].uc_size = np.array([2, 2])
Hp[2].uc_pos = np.array([0, 1])

z = zm_state(2, 1, pxp)
z2 = zm_state(2, 1, pxp, 1)

k = [0, 0]
block_refs = pxp_syms.find_block_refs(k)
if z.ref in block_refs:
    neel_loc = find_index_bisection(z.ref, block_refs)
else:
    neel_loc = find_index_bisection(z2.ref, block_refs)

for n in range(0, len(Hp)):
    Hp[n].gen(k)

psi_mom = np.zeros(np.size(block_refs))
psi_mom[neel_loc] = 1


def fidelity_eval(psi_energy, e, t):
    evolved_state = time_evolve_state(psi_energy, e, t)
    f = np.abs(np.vdot(evolved_state, psi_energy))**2
    return f