def AngleSpectrum(number_particles, noEV, gamma, hopping, angle):
    """
    AngleSpectrum(number_particles, noEV, gamma, hopping, angle):
    
    computes the energy eigenspectrum as a function of the angle of the dipoles
    with the chain axis given an unit interaction V and a hopping J

    parameters of the function:
        number_particles: number of particles in the problem
        noEV: number of eigenvalues being calculated
        gamma: opening angle of the zig-zag chain
        hopping: hopping parameter in units of interaction V
        angle: array containing the angles as a multiple of **PI**
    """

    """ default values for other methods that are being called by the current
        function """
    spectrum = 1  # ensures that the spectrum is calculated in EigSys_HalfFilling
    independet_v1_v2 = 1  # makes v1 and v2 independent of each other
    number_sites = 2 * number_particles  # condition for half-filling
    interaction_strength = 1  # unit of energy
    #    number_particles = 6
    #    noEV = 5*number_sites #degeneracy of GS requires noEV>number_sites
    #    hopping = .1
    #    gamma = 2*pi/3
    #    angle = linspace(-.8,-.7,41)

    """ intialization of variables that will be stored for later use """
    eigval = zeros((angle.shape[0], noEV), dtype=float)
    degeneracies = zeros((angle.shape[0], 1))
    v1 = zeros((angle.shape[0], 1))
    v2 = zeros((angle.shape[0], 1))
    v3 = zeros((angle.shape[0], 1))

    """ actual method call """
    if __name__ == "DiagonalizationMethods":
        info("main line")
        pool = Pool()
        """ invocation of the eigenvalue procedure """
        it = [
            pool.apply_async(
                EigSys_HalfFilling,
                (
                    number_particles,
                    number_sites,
                    hopping,
                    interaction_strength,
                    angle[angle_idx],
                    noEV,
                    spectrum,
                    gamma,
                    independet_v1_v2,
                ),
            )
            for angle_idx in range(0, angle.shape[0])
        ]
        for ridx in it:
            angle_idx = nonzero(angle == ridx.get()[0])
            eigval[angle_idx, :] = ridx.get()[1]  # floor(10*around(real(ridx.get()[1]),decimals = 2))/10
            degeneracies[angle_idx] = sum((eigval[angle_idx, :] == eigval[angle_idx, 0]).astype(int))
            v1[angle_idx] = ridx.get()[2]
            v2[angle_idx] = ridx.get()[3]
            v3[angle_idx] = ridx.get()[4]
            print "angle:", angle[angle_idx], "\nground-state degeneracy:", degeneracies[angle_idx]

        filename = (
            "FigureData/"
            + now
            + "_AngleSpectrum_N"
            + str(number_particles)
            + "_J"
            + str(hopping).replace(".", "-")
            + "_vdd"
            + str(interaction_strength).replace(".", "-")
        )
        save(filename + "_EigVals", eigval)
        save(filename + "_angle", angle)
        print "saved: " + filename
def EigSys_HalfFilling(number_particles, number_sites, J, vNN, angle_fraction, noEV, spectrum, gamma, independent_v1_v2):
    ''' Hopping matrix element J and angle angle_fraction as fraction of pi
        gamma is angle of lattice, i.e. gamma = 2*pi/3 = 120° for single chain of 
        hexagonal lattice'''
    
    info('Diagonalization Module')    
    
    set_printoptions(precision=4, suppress=True, linewidth = 100)
    
    vNNN = 0*vNN
    if independent_v1_v2 ==1:
        v1 = vNN*(cos(pi*angle_fraction)+sin(pi*angle_fraction))
        v2 = vNN*(cos(pi*angle_fraction)-sin(pi*angle_fraction))
        v3 = vNNN
    else:
        v1 = vNN*(1-3*cos(pi - gamma/2 - pi*angle_fraction)**2) / (-.25*(2+6*cos(gamma)))
        v2 = vNN*(1-3*cos(gamma/2 - pi*angle_fraction)**2)/ (-.25*(2+6*cos(gamma)))
        v3 = vNNN*(1-3*cos(pi/2 - pi*angle_fraction)**2)/sqrt(2*(1-cos(gamma)))/ (-.25*(2+6*cos(gamma)))
    vp = (v1+v2)/2
    vm = (v1-v2)/2
    
    print ' symmetric nn-int: %s \n antisymmetric nn-int: %s \n nnn-int: %s \n hopping: %s' % ( vp, vm, v3, J)
    


    basis_name = 'HamiltonianData/BasisStates_N'+str(number_particles)+'_L'+str(number_sites)
    if isfile(basis_name+'.npy') == False:
        number_states = int(round(binom(number_sites, number_particles)))
        full_base = asarray(list(itertools.product(range(2), repeat=number_sites)), dtype=int)
        base = zeros((number_states,number_sites))
        midx = 0
        for m in range(0, full_base.shape[0]):
            if sum(full_base[m,:])==number_particles:
                print m, midx
                base[midx,:]=full_base[m,:]
                midx = midx+1
        save(basis_name, base)
        print 'saved new basis:', basis_name
    elif isfile(basis_name+'.npy') == True:
        print 'loading basis:', basis_name
        base = load(basis_name+'.npy')
    
    
    number_states = base.shape[0]


    nn_ham_name = 'HamiltonianData/NearestNeighbor_HoppingHamiltonian_N'+str(number_particles)+'_L'+str(number_sites)                    
    if isfile(nn_ham_name+'.npy') == False:
        nn_ham = nn_hopping(base, number_particles, number_sites)
        save(nn_ham_name, nn_ham)
        print 'saved new nearest-neighbor hopping Hamiltonian: ', nn_ham_name
    elif isfile(nn_ham_name+'.npy') == True:
        print 'loading nearest-neighbor hopping Hamiltonian: ', nn_ham_name
        nn_ham = load(nn_ham_name+'.npy')
    '''Commenting out the NNN hopping'''       
#    nnn_ham_name = 'HamiltonianData/NextNearestNeighbor_HoppingHamiltonian_N'+str(number_particles)+'_L'+str(number_sites)                    
#    if isfile(nnn_ham_name+'.npy') == False:
#        nnn_ham = nnn_hopping(base, number_particles, number_sites)
#        save(nnn_ham_name, nnn_ham)
#        print 'saved new next-nearest-neighbor hopping Hamiltonian: ', nnn_ham_name
#    elif isfile(nnn_ham_name+'.npy') == True:
#        print 'loading next-nearest-neighbor hopping Hamiltonian: ', nnn_ham_name
#        nnn_ham = load(nnn_ham_name+'.npy')
        
    ham = J*nn_ham#+0*(J/sqrt(2*(1-cos(gamma))))*nnn_ham

    if (ham.todense() == (ham.todense()).transpose()).all() != True:
        print (ham.todense() == (ham.todense()).transpose()).all()
        print 'Hopping is non-symmetric!'
        return
        
    print 'generating interaction Hamiltonian'
    if vNN == 0:
        print 'free fermions, no interactions'
    else:
        for idx_state in range(0,number_states):
            hidx, v = int_ham(base, number_particles, number_sites, gamma, vNN, vNNN, angle_fraction, idx_state, independent_v1_v2)
            ham[hidx, hidx] = v
        
            
    if spectrum == 0:
        print 'calculating eigenvectors and spectrum'
        eig_val, eig_vec = la.eigsh(ham, k=noEV, which='SA', maxiter=10000, return_eigenvectors=True)
    
        index_ev = eig_val.ravel().argsort()
        eigval = eig_val[index_ev]
        eigvec = eig_vec[:,index_ev]

        return eigval, eigvec, base
        
    elif spectrum == 1:

        print 'calculating spectrum'
        eig_val = la.eigsh(ham, k=noEV, which='SA', maxiter = 10000, return_eigenvectors=False)
        
        index_ev = eig_val.ravel().argsort()
        eigval = eig_val[index_ev]
        
        return angle_fraction, eigval, v1, v2, v3, J, vNN
def HoppingSpectrum(number_particles, noEV, gamma, angle, hopping):
    """ computes the eigenvalue spectrum for given interactions as a function 
        of the hopping in units of interaction V
    
        parameters of the function:
            number_particles: number of particles in the problem
            noEV: number of eigenvalues being calculated
            gamma: opening angle of the zig-zag chain
            angle: array containing the angles as a multiple of **PI**
            hopping: hopping in units of interaction V
    """

    """ default values for other methods that are being called by the current
        function """
    spectrum = 1  # ensures that the spectrum is calculated in EigSys_HalfFilling
    independent_v1_v2 = 1  # makes v1 and v2 independent of each other
    number_sites = 2 * number_particles  # condition for half-filling
    interaction_strength = 1  # unit of energy

    """ intialization of variables that will be stored for later use """
    eigval = zeros((len(hopping), noEV), dtype=float)
    v1 = zeros((hopping.shape[0], 1))
    v2 = zeros((hopping.shape[0], 1))
    v3 = zeros((hopping.shape[0], 1))

    """ actual method call """
    if __name__ == "DiagonalizationMethods":
        info("main line")
        pool = Pool()
        """ invocation of eigenvalue procedure """
        it = [
            pool.apply_async(
                EigSys_HalfFilling,
                (
                    number_particles,
                    number_sites,
                    hopping[idx],
                    interaction_strength,
                    angle,
                    noEV,
                    spectrum,
                    gamma,
                    independent_v1_v2,
                ),
            )
            for idx in range(len(hopping))
        ]
        for ridx in it:
            idx = nonzero(hopping == ridx.get()[5])
            v1 = ridx.get()[2]
            v2 = ridx.get()[3]
            v3 = ridx.get()[4]
            eigval[idx, :] = ridx.get()[1]
            print "hopping:", hopping[idx], "interactions: ", v1, v2, v3

    filename = (
        "FigureData/"
        + now
        + "_HoppingSpectrum-nnhopping_N"
        + str(number_particles)
        + "_vdd"
        + str(interaction_strength).replace(".", "-")
        + "_Theta"
        + str(angle).replace(".", "-")
    )
    save(filename + "_EigVals", eigval)
    save(filename + "_hopping", hopping)
    print "saved: " + filename