using SparseArrays, LinearAlgebra, Arpack
include("io/io_helper.jl")


function diagonalize(ham::Hamiltonian, param::Dict{Any,Any})
    """ Performs the diagonalization as specified in the paramter dictionary.
        Done either by iterated Arnoldi method with ARPACK (when full_diag is
        set to `false`) or by full diagonalization.

        Notes:
         -  Julia has a matrix-independent iteration number of 300 per default,
            this is potentially problematic. Needs to be adjusted in some cases.
    """
    sparse_ham = sparse(ham.row, ham.col, ham.data, ham.n_fock, ham.n_fock)

    if ham.n_fock > 1
        @info "Starting to diagonalize the Hamiltonian." n_fock=Int(ham.n_fock)
        if get(param, "full_diag", false)
            # Full diagonalization with built-in method.
            time = @elapsed mem = @allocated F = eigen(Matrix(sparse_ham))
            @info "Done computing the full spectrum." time=time allocated=MemoryTag(mem) spectrum=F.values
            return F.values, F.vectors
        else
            # Arnoldi method with ARPACK.
            which_map = Dict([
                ("SA", :SR)
            ])
            # Here, we set the default values that are otherwise overwritten
            # if specified in the parameter dictionary.
            time = @elapsed mem = @allocated ev, est = eigs(
                sparse_ham,
                nev=get(param, "n_eigenvalues", 10),
                which=which_map[get(param, "ev_type", "SA")],
                tol=get(param, "tol", 1e-15),
                maxiter=get(param, "max_iter", 10*ham.n_fock)
            )
            @info "Done computing the lower spectrum." time=time allocated=MemoryTag(mem) spectrum=ev
            return ev, est
        end
    end
    @info "Trivial 1x1 matrix to diagonalize."
    return Matrix(sparse_ham)[1,1], [1]
end