Example #1
0
# construct random J matrix
Jij = tfim.Jij_instance(N, J, "bimodal", Jij_seed)

# In[6]:

# List out all the spin_states, corresponding indices and energies
Energies = -tfim.JZZ_SK_ME(basis, Jij)
for index in range(2**N):
    print(index, basis.state(index), Energies[index])

# In[7]:

# Build 2nd order approximated matrix

GS_energy, GS_indices = tfim_perturbation.GS(Energies)

H_app_0 = tfim_perturbation.H_app_0(GS_energy, GS_indices)

H_app_1 = tfim_perturbation.H_app_1(basis, GS_indices, N)

H_app_2 = tfim_perturbation.H_app_2(basis, Jij, GS_indices, N, GS_energy)

print(H_app_2)

# In[8]:

# Build exact matrix
V_exc = tfim_perturbation.V_exact(basis, lattice)

H_0_exc = tfim_perturbation.H_0_exact(Energies)
Example #2
0
def tfim_analysis(L,
                  Jij_seed,
                  perturbation_order,
                  h_x_range=np.arange(0, 0.005, 0.0001),
                  PBC=True,
                  J=1):
    #Initialize the output dictionary containing all the information that we want to know about a specific instance
    #   - isEmpty
    #   - isWorking
    #   both of which contains logical True or False values

    #Initial set up
    info = {}
    # Configure the number of spins to the correct format for analysis
    L = [L]

    # Build lattice and basis
    ###################################
    lattice = tfim.Lattice(L, PBC)
    N = lattice.N
    basis = tfim.IsingBasis(lattice)
    ###################################

    # construct random J matrix
    Jij = tfim.Jij_instance(N, J, "bimodal", Jij_seed)

    # List out all the spin_states, corresponding indices and energies
    Energies = -tfim.JZZ_SK_ME(basis, Jij)
    # for index in range(2 ** N):
    #     print(index, basis.state(index), Energies[index])
    GS_energy, GS_indices = tfim_perturbation.GS(Energies)

    # Specify perturbation order
    if perturbation_order == 3:
        analysis_func = tfim_perturbation.app_3_eigensystem_general_matrices
        H_app_3 = tfim_perturbation.H_app_3(basis, Jij, GS_indices, N,
                                            GS_energy)
        isEmpty = np.allclose(H_app_3,
                              np.zeros((len(GS_indices), len(GS_indices))))
    elif perturbation_order == 4:
        analysis_func = tfim_perturbation.app_4_eigensystem_general_matrices
        isEmpty = False
    # Check to see if the max order perturbative term is empty and store this information in "info"
    info['isEmpty'] = isEmpty

    # Calculate approximated eigenvalues and eigenstates for range(h_x)
    app_eigenvalues, app_eigenstates = analysis_func(GS_indices, GS_energy,
                                                     h_x_range, J, N, basis,
                                                     Jij)
    # Calculate exact eigenvalues and eigenstates for range(h_x)
    exc_eigenvalues, exc_eigenstates = tfim_perturbation.exc_eigensystem(
        basis, h_x_range, lattice, Energies)

    # Extract exact ground states
    exc_GS_eigenstates = np.zeros(
        (len(h_x_range), len(GS_indices), len(GS_indices)))

    for i in range(len(h_x_range)):
        for m, j in enumerate(GS_indices):
            for n, k in enumerate(GS_indices):
                exc_GS_eigenstates[i, m, n] = exc_eigenstates[i, j, n]

    # Extract exact ground energy
    reordered_app_eigenstates = np.zeros(
        [len(h_x_range), len(GS_indices),
         len(GS_indices)])
    epsilon = 1 * 10**(-6)

    for h_x_index in range(len(h_x_range)):
        if h_x_index < 2:
            reordered_app_eigenstates[h_x_index] = app_eigenstates[h_x_index]
        else:
            for k in range(len(GS_indices) // 2):
                fidelity_array = []
                for v1 in [
                        reordered_app_eigenstates[h_x_index - 1, :, 2 * k],
                        reordered_app_eigenstates[h_x_index - 1, :, 2 * k + 1]
                ]:
                    for v2 in [
                            app_eigenstates[h_x_index, :, 2 * k],
                            app_eigenstates[h_x_index, :, 2 * k + 1]
                    ]:
                        fidelity_array = np.append(
                            fidelity_array, tfim_perturbation.fidelity(v1, v2))
                if abs(fidelity_array[0] - max(fidelity_array)) < epsilon:
                    reordered_app_eigenstates[
                        h_x_index, :, 2 * k] = app_eigenstates[h_x_index, :,
                                                               2 * k]
                    reordered_app_eigenstates[h_x_index, :,
                                              2 * k + 1] = app_eigenstates[
                                                  h_x_index, :, 2 * k + 1]
                else:
                    reordered_app_eigenstates[
                        h_x_index, :, 2 * k] = app_eigenstates[h_x_index, :,
                                                               2 * k + 1]
                    reordered_app_eigenstates[h_x_index, :,
                                              2 * k + 1] = app_eigenstates[
                                                  h_x_index, :, 2 * k]

    reordered_exc_GS_eigenstates = np.zeros(
        [len(h_x_range), len(GS_indices),
         len(GS_indices)])
    epsilon = 1 * 10**(-12)

    for h_x_index in range(len(h_x_range)):
        if h_x_index < 2:
            reordered_exc_GS_eigenstates[h_x_index] = exc_GS_eigenstates[
                h_x_index]
        else:
            for k in range(len(GS_indices) // 2):
                fidelity_array = []
                for v1 in [
                        reordered_exc_GS_eigenstates[h_x_index - 1, :, 2 * k],
                        reordered_exc_GS_eigenstates[h_x_index - 1, :,
                                                     2 * k + 1]
                ]:
                    for v2 in [
                            exc_GS_eigenstates[h_x_index, :, 2 * k],
                            exc_GS_eigenstates[h_x_index, :, 2 * k + 1]
                    ]:
                        fidelity_array = np.append(
                            fidelity_array, tfim_perturbation.fidelity(v1, v2))
                if abs(fidelity_array[0] - max(fidelity_array)) < epsilon:
                    reordered_exc_GS_eigenstates[
                        h_x_index, :, 2 * k] = exc_GS_eigenstates[h_x_index, :,
                                                                  2 * k]
                    reordered_exc_GS_eigenstates[
                        h_x_index, :,
                        2 * k + 1] = exc_GS_eigenstates[h_x_index, :,
                                                        2 * k + 1]
                else:
                    reordered_exc_GS_eigenstates[
                        h_x_index, :, 2 * k] = exc_GS_eigenstates[h_x_index, :,
                                                                  2 * k + 1]
                    reordered_exc_GS_eigenstates[
                        h_x_index, :,
                        2 * k + 1] = exc_GS_eigenstates[h_x_index, :, 2 * k]
    # Calculate and plot energy errors
    corrected_exc_eigenvalues = np.zeros((len(GS_indices), len(h_x_range)))

    for i in range(len(GS_indices)):
        for j in range(len(h_x_range)):
            corrected_exc_eigenvalues[i, j] = exc_eigenvalues[i, j]

    error_array = np.absolute(corrected_exc_eigenvalues - app_eigenvalues)

    # Curve fit
    coeff_matrix = np.zeros((len(GS_indices), 2))
    for i in range(len(GS_indices)):
        pars, cov = curve_fit(f=power_law,
                              xdata=h_x_range,
                              ydata=error_array[i])
        coeff_matrix[i] = pars

    # Check to see if perturbation is working and store it in the info dictionary
    if info['isEmpty'] == False:
        judgment, error_classical_GS_index = isWorking(coeff_matrix,
                                                       perturbation_order)
        info['isWorking'] = bool(judgment)
        info['error state index'] = error_classical_GS_index
        info['error order'] = coeff_matrix[error_classical_GS_index, 1]
    else:
        info['isWorking'] = None
        info['error order'] = None
        info['error state index'] = None

    # return info dictionary
    return info, coeff_matrix[:, 1]
Example #3
0
def lanczos(L, seed, h_x_range, PBC, h_z, maxiter):

    # In[3]:

    start_time = time.time()

    def Jij_2D_NN(seed, N, PBC, xwidth, yheight, lattice, p):
        def bond_list_unequal(seed, N, PBC, xwidth, yheight, p):
            # p is the probability distribution of ferromagnetic bonds
            np.random.seed(seed)
            if PBC == True:
                num_of_bonds = 2 * N
            else:
                num_of_bonds = (xwidth - 1) * (yheight) + (xwidth) * (yheight -
                                                                      1)
            i = [np.random.random() for _ in range(num_of_bonds)]
            # print(i)
            a = np.zeros(len(i))
            for index, prob_seed in enumerate(i):
                if prob_seed <= p:
                    a[index] += 1
                else:
                    a[index] -= 1
            return a

        def make_Jij(N, b_list, lattice):
            #Goes through the list of bonds to make the jij matrix that tells you how all of the spins are bonded to each other

            bond_index = 0
            Jij = np.zeros((N, N))
            for i in range(0, N):
                NNs = lattice.NN(i)
                for j in NNs:
                    if Jij[i][j] == 0:
                        Jij[i][j] = b_list[bond_index]
                        Jij[j][i] = b_list[bond_index]
                        bond_index += 1
            return Jij

        b_list = bond_list_unequal(seed, N, PBC, xwidth, yheight, p)
        return make_Jij(N, b_list, lattice)

    # In[4]:

    # Build lattice and basis
    lattice = tfim.Lattice(L, PBC)
    N = lattice.N
    basis = tfim.IsingBasis(lattice)

    # In[5]:

    #construct random J matrix
    Jij = Jij_2D_NN(seed, N, PBC, L[0], L[1], lattice, p=0.5)

    # In[6]:

    # List out all the spin_states, corresponding indices and energies
    Ising_energy_arr = np.zeros(2**N)
    for index in range(2**N):
        state = basis.state(index)
        # modify state from 0 and 1 base to -1, 1 base
        for i in range(N):
            if state[i] == 0:
                state[i] -= 1
        Ising_energy = 0
        for i in range(N):
            for j in range(i + 1, N, 1):
                bond_energy = Jij[i, j] * state[i] * state[j]
                Ising_energy += bond_energy
        Ising_energy_arr[index] = Ising_energy
        print(index, basis.state(index), Ising_energy)
    print("----%s seconds ----" % (time.time() - start_time))

    # In[7]:

    GS_energy, GS_indices = tfim_perturbation.GS(Ising_energy_arr)

    # initialize Lanczos vector
    v0 = np.zeros(2**N)
    for i in GS_indices:
        v0[i] = 1

    # In[8]:

    # modified exact Hamiltonians using compressed sparse row matrices
    def V_exact_csr(basis, lattice):
        row = []
        col = []
        for ket in range(basis.M):
            state = basis.state(ket)
            for i in range(lattice.N):
                basis.flip(state, i)
                bra = basis.index(state)
                row.append(bra)
                col.append(ket)
                basis.flip(state, i)
        data = np.ones(len(col))
        V_exact = sparse.csr_matrix((data, (np.array(row), np.array(col))),
                                    shape=(2**N, 2**N))
        return V_exact

    def H_0_exact_csr(Energies):
        return sparse.diags(Energies)

    # In[9]:

    # modified function to eigendecompose the exact Hamiltonian using Lanczos method
    def exc_eigensystem(basis, h_x_range, lattice, Energies):
        # Calculate exact eigenvalues and eigenstates for range(h_x)
        exc_eigenvalues = np.zeros(len(h_x_range))
        first_excited_exc_energies = np.zeros(len(h_x_range))
        exc_eigenstates = np.zeros((len(h_x_range), basis.M))
        V_exc_csr = V_exact_csr(basis, lattice)
        H_0_exc_csr = H_0_exact_csr(Energies)
        for j, h_x in enumerate(h_x_range):
            H = H_0_exc_csr - V_exc_csr.multiply(h_x)
            exc_eigenvalue, exc_eigenstate = spla.eigsh(
                H,
                k=2,
                which='SA',
                v0=v0,
                maxiter=maxiter,
                tol=1e-5,
                return_eigenvectors=True)
            print("----%s seconds for h_x = %s----" %
                  (time.time() - start_time, h_x))

            exc_eigenvalues[j] = exc_eigenvalue[0]
            first_excited_exc_energies[j] = exc_eigenvalue[1]
            for k in range(basis.M):
                exc_eigenstates[j][k] = exc_eigenstate[k, 0]
        return V_exc_csr, H_0_exc_csr, exc_eigenvalues, first_excited_exc_energies, exc_eigenstates

    # In[10]:

    # Calculate exact eigenvalues and eigenstates for range(h_x)
    V_exc, H_0_exc, exc_eigenvalues, first_excited__exc_energies, exc_eigenstates = exc_eigensystem(
        basis, h_x_range, lattice, Ising_energy_arr)

    print("----%s seconds ----" % (time.time() - start_time))

    # In[13]:

    final = h_x_range[-1]
    init = h_x_range[1]
    num_steps = len(h_x_range)
    # first and second derivative of ground state energy per site
    first_derivative_exc_eigenvalues = np.gradient(
        exc_eigenvalues, (final - init) / float(num_steps))
    second_derivative_exc_eigenvalues = np.gradient(
        first_derivative_exc_eigenvalues, (final - init) / float(num_steps))

    # compute susciptibility

    # In[16]:

    chi_aa_matrix = np.zeros((len(h_x_range), lattice.N))
    for i, h_x in enumerate(h_x_range):
        for a in range(lattice.N):
            sigma_z = np.zeros(basis.M)
            for ket in range(basis.M):
                state = basis.state(ket)
                if state[a] == 1:
                    sigma_z[ket] += 1
                else:
                    sigma_z[ket] -= 1
            longitudinal_energy = spla.eigsh(H_0_exc - V_exc.multiply(h_x) -
                                             h_z * sparse.diags(sigma_z),
                                             k=1,
                                             which='SA',
                                             v0=v0,
                                             tol=1e-5,
                                             maxiter=maxiter,
                                             return_eigenvectors=False)[0]
            print("----%s seconds for h_x = %s----" %
                  (time.time() - start_time, h_x))
            chi_aa = 2. * abs(
                abs(exc_eigenvalues[i]) - abs(longitudinal_energy)) / (h_z**2)
            chi_aa_matrix[i, a] += chi_aa

    # In[18]:

    chi_ab_matrix = np.zeros((len(h_x_range), basis.N, basis.N))
    for i, h_x in enumerate(h_x_range):
        for a in range(lattice.N):
            sigma_z_a = np.zeros(basis.M)
            for ket in range(basis.M):
                state = basis.state(ket)
                if state[a] == 1:
                    sigma_z_a[ket] += 1
                else:
                    sigma_z_a[ket] -= 1
            for b in range(a, lattice.N, 1):
                sigma_z_b = np.zeros(basis.M)
                for ket in range(basis.M):
                    state = basis.state(ket)
                    if state[b] == 1:
                        sigma_z_b[ket] += 1
                    else:
                        sigma_z_b[ket] -= 1
                H = H_0_exc - V_exc.multiply(h_x) - (
                    sparse.diags(sigma_z_a) +
                    sparse.diags(sigma_z_b)).multiply(h_z)
                longitudinal_energy = spla.eigsh(H,
                                                 k=1,
                                                 which='SA',
                                                 v0=v0,
                                                 tol=1e-5,
                                                 maxiter=maxiter,
                                                 return_eigenvectors=False)[0]
                print("----%s seconds for h_x = %s----" %
                      (time.time() - start_time, h_x))
                chi_ab = abs(
                    abs(exc_eigenvalues[i]) - abs(longitudinal_energy)) / (
                        h_z**
                        2.) - 0.5 * (chi_aa_matrix[i, a] + chi_aa_matrix[i, b])
                chi_ab_matrix[i, a, b] += chi_ab
                chi_ab_matrix[i, b, a] += chi_ab
            # adding the diagonal elements
            for c in range(N):
                chi_ab_matrix[i, c, c] = chi_aa_matrix[i, c]

    chi_arr = np.zeros(len(h_x_range))
    for i, h_x in enumerate(h_x_range):
        chi_arr[i] += np.sum(chi_ab_matrix[i])
    print("----%s seconds ----" % (time.time() - start_time))

    # compute structure factor
    S_SG_arr = np.zeros(np.shape(h_x_range))
    for i, h_x in enumerate(h_x_range):
        psi0 = exc_eigenstates[i]
        for a in range(N):
            for b in range(N):
                sigma_z_a = np.zeros(basis.M)
                sigma_z_b = np.zeros(basis.M)
                for ket in range(basis.M):
                    state = basis.state(ket)
                    if state[a] == 1:
                        sigma_z_a[ket] += 1
                    else:
                        sigma_z_a[ket] -= 1
                for ket in range(basis.M):
                    state = basis.state(ket)
                    if state[b] == 1:
                        sigma_z_b[ket] += 1
                    else:
                        sigma_z_b[ket] -= 1
                S_ab = psi0 @ sparse.diags(sigma_z_a) @ sparse.diags(
                    sigma_z_b) @ psi0.T
                S_SG_arr[i] += S_ab**2.
    print("----%s seconds ----" % (time.time() - start_time))

    return N, h_x_range, exc_eigenvalues, first_excited__exc_energies, second_derivative_exc_eigenvalues, chi_arr, S_SG_arr
Example #4
0
def main():
    # Parse command line arguments
    ###################################

    parser = argparse.ArgumentParser(description=(
        "Build approximate matrices using first and second order perturbation theory and return its eigenvalues and eigenstates"
    ))

    parser.add_argument('lattice_specifier',
                        help=("Linear dimensions of the system"))

    parser.add_argument('-PBC', type=bool, default=True, help="Specifying PBC")

    parser.add_argument('-J',
                        type=float,
                        default=1.0,
                        help='Nearest neighbor Ising coupling')

    parser.add_argument(
        '-seed',
        type=int,
        default=5,
        help="Specifying the seed for generating random Jij matrices")

    parser.add_argument('--h_min',
                        type=float,
                        default=0.0,
                        help='Minimum value of the transverse field')
    parser.add_argument('--h_max',
                        type=float,
                        default=0.1,
                        help='Maximum value of the transverse field')
    parser.add_argument('--dh',
                        type=float,
                        default=0.01,
                        help='Tranverse fied step size')

    parser.add_argument('-o', default='output', help='output filename base')

    parser.add_argument('-d',
                        default='Output_file',
                        help='output directory base')

    args = parser.parse_args()

    ###################################
    # Parameter specification
    out_filename_base = args.o

    # Transverse field
    h_x_range = np.arange(args.h_min, args.h_max + args.dh / 2, args.dh)

    L = [int(args.lattice_specifier)]
    PBC = args.PBC
    J = args.J
    seed = args.seed

    # Build lattice and basis
    lattice = tfim.Lattice(L, PBC)
    N = lattice.N
    basis = tfim.IsingBasis(lattice)

    # Construct random J matrix
    Jij = tfim.Jij_instance(N, J, "bimodal", seed)
    ###################################

    Energies = -tfim.JZZ_SK_ME(basis, Jij)
    GS_energy, GS_indices = tfim_perturbation.GS(Energies)

    ###################################

    H_0 = tfim_perturbation.H_0(GS_energy, GS_indices)
    H_app_1 = tfim_perturbation.H_app_1(basis, GS_indices, N)
    H_app_2 = tfim_perturbation.H_app_2(basis, Jij, GS_indices, N, GS_energy)

    ###################################
    # Diagonalization loop over h_x_range on H_app

    app_eigenvalues = np.zeros((len(GS_indices), len(h_x_range)))
    app_eigenstates = np.zeros(
        (len(GS_indices), len(GS_indices), len(h_x_range)))

    for j, h_x in enumerate(h_x_range):
        H_app = tfim_perturbation.H_app(h_x, H_0, H_app_1, H_app_2, J)
        app_eigenvalue, app_eigenstate = np.linalg.eigh(H_app)
        for i in range(len(GS_indices)):
            app_eigenvalues[i][j] = app_eigenvalue[i]
            for k in range(len(GS_indices)):
                app_eigenstates[i][k][j] = app_eigenstate[i][k]

    ###################################
    # Make output directory

    Output = args.d

    os.mkdir(Output)
    os.chdir(Output)

    ###################################
    # Output Eigenvalue file

    out_filename_E = out_filename_base + '.dat'

    # Quantities to write Eigenvalue ouput file

    phys_keys_E = []

    for i in range(len(app_eigenvalues)):
        eigenvalue_num = 'Eigenvalue ' + str(i + 1)
        phys_keys_E.append(eigenvalue_num)

    phys_keys_E.insert(0, 'h_x')
    phys_E = {}  # Dictionary for values

    # Setup output Eigenvalue data files

    parameter_string = ("L = {}, PBC = {}, J = {}".format(L, PBC, J))

    width = 25
    precision = 16
    header_list = phys_keys_E
    header = ''.join(
        ['{:>{width}}'.format(head, width=width) for head in header_list])
    out_eigenvalue_file = open(out_filename_E, 'w')
    print("\tData will write to {}".format(out_filename_E))
    out_eigenvalue_file.write('#\ttfim_diag parameters:\t' + parameter_string +
                              '\n' + '#' + header[1:] + '\n')

    # Put eigenvalues in phys_E dictionary

    for i, h_x in enumerate(h_x_range):
        phys_E['h_x'] = h_x
        for j, key in enumerate(phys_keys_E[1:]):
            phys_E[key] = app_eigenvalues[j, i]

    # Write eigenvalues to output files

        data_list = [phys_E[key] for key in phys_keys_E]
        data_line = ''.join([
            '{:{width}.{prec}e}'.format(data, width=width, prec=precision)
            for data in data_list
        ])
        out_eigenvalue_file.write(data_line + '\n')

    # Close files

    out_eigenvalue_file.close()

    ###################################

    # Output Eigenstate files

    for file_num in range(len(app_eigenstates)):

        out_filename_V = out_filename_base + '_' + str(file_num) + '.dat'

        # Quantities to write Eigenstate output file

        phys_keys_V = []

        for i in range(len(app_eigenstates)):
            basis = 'Basis ' + str(i + 1)
            phys_keys_V.append(basis)

        phys_keys_V.insert(0, 'h_x')
        phys_V = {}  # Dictionary for values

        # Setup output Eigenstate data files

        parameter_string = ("L = {}, PBC = {}, J = {}".format(L, PBC, J))

        width = 25
        precision = 16
        header_list = phys_keys_V
        header = ''.join(
            ['{:>{width}}'.format(head, width=width) for head in header_list])
        out_eigenstate_file = open(out_filename_V, 'w')
        print("\tData will write to {}".format(out_filename_V))
        out_eigenstate_file.write('#\ttfim_diag parameters:\t' +
                                  parameter_string + '\n' + '#' + header[1:] +
                                  '\n')

        # Put eigenstates in phys_V dictionary

        for i, h_x in enumerate(h_x_range):
            phys_V['h_x'] = h_x
            for j, key in enumerate(phys_keys_V[1:]):
                phys_V[key] = app_eigenstates[file_num][j, i]

        # Write eigenvalues to output files

            data_list = [phys_V[key] for key in phys_keys_V]
            data_line = ''.join([
                '{:{width}.{prec}e}'.format(data, width=width, prec=precision)
                for data in data_list
            ])
            out_eigenstate_file.write(data_line + '\n')

        # Close files

        out_eigenstate_file.close()

    #######################################################

    # Exit "Output" directory

    os.chdir("../")