Exemple #1
0
    def test_hf_state_plane_wave_basis_lowest_single_determinant_state(self):
        grid_length = 7
        dimension = 1
        spinless = True
        n_particles = 4
        length_scale = 2.0

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless)
        hamiltonian_sparse = get_sparse_operator(hamiltonian)

        hf_state = hartree_fock_state_jellium(grid,
                                              n_particles,
                                              spinless,
                                              plane_wave=True)

        HF_energy = expectation(hamiltonian_sparse, hf_state)

        for occupied_orbitals in permutations([1] * n_particles + [0] *
                                              (grid_length - n_particles)):
            state_index = numpy.sum(2**numpy.array(occupied_orbitals))
            HF_competitor = csr_matrix(([1.0], ([state_index], [0])),
                                       shape=(2**grid_length, 1))

            self.assertLessEqual(
                HF_energy, expectation(hamiltonian_sparse, HF_competitor))
Exemple #2
0
def dual_basis_jellium_hamiltonian(grid_length,
                                   dimension=3,
                                   wigner_seitz_radius=10.,
                                   n_particles=None,
                                   spinless=True):
    """Return the jellium Hamiltonian with the given parameters.

    Args:
        grid_length (int): The number of spatial orbitals per dimension.
        dimension (int): The dimension of the system.
        wigner_seitz_radius (float): The radius per particle in Bohr.
        n_particles (int): The number of particles in the system.
                           Defaults to half filling if not specified.
    """
    n_qubits = grid_length**dimension
    if not spinless:
        n_qubits *= 2

    if n_particles is None:
        # Default to half filling fraction.
        n_particles = n_qubits // 2

    if not (0 <= n_particles <= n_qubits):
        raise ValueError('n_particles must be between 0 and the number of'
                         ' spin-orbitals.')

    # Compute appropriate length scale.
    length_scale = wigner_seitz_length_scale(wigner_seitz_radius, n_particles,
                                             dimension)

    grid = Grid(dimension, grid_length, length_scale)
    hamiltonian = jellium_model(grid, spinless=spinless, plane_wave=False)
    hamiltonian = normal_ordered(hamiltonian)
    hamiltonian.compress()
    return hamiltonian
Exemple #3
0
    def test_hf_state_energy_close_to_ground_energy_at_high_density(self):
        grid_length = 8
        dimension = 1
        spinless = True
        n_particles = grid_length**dimension // 2

        # High density -> small length_scale.
        length_scale = 0.25

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless)
        hamiltonian_sparse = get_sparse_operator(hamiltonian)

        hf_state = hartree_fock_state_jellium(grid,
                                              n_particles,
                                              spinless,
                                              plane_wave=True)

        restricted_hamiltonian = jw_number_restrict_operator(
            hamiltonian_sparse, n_particles)

        E_g = get_ground_state(restricted_hamiltonian)[0]
        E_HF_plane_wave = expectation(hamiltonian_sparse, hf_state)

        self.assertAlmostEqual(E_g, E_HF_plane_wave, places=5)
Exemple #4
0
    def test_sum_of_ordered_terms_equals_full_hamiltonian(self):
        grid_length = 4
        dimension = 2
        wigner_seitz_radius = 10.0
        inverse_filling_fraction = 2
        n_qubits = grid_length**dimension

        # Compute appropriate length scale.
        n_particles = n_qubits // inverse_filling_fraction

        # Generate the Hamiltonian.
        hamiltonian = dual_basis_jellium_hamiltonian(grid_length, dimension,
                                                     wigner_seitz_radius,
                                                     n_particles)

        terms = simulation_ordered_grouped_dual_basis_terms_with_info(
            hamiltonian)[0]
        terms_total = sum(terms, FermionOperator.zero())

        length_scale = wigner_seitz_length_scale(wigner_seitz_radius,
                                                 n_particles, dimension)

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless=True, plane_wave=False)
        hamiltonian = normal_ordered(hamiltonian)
        self.assertTrue(terms_total.isclose(hamiltonian))
Exemple #5
0
    def test_hf_state_energy_same_in_plane_wave_and_dual_basis(self):
        grid_length = 4
        dimension = 1
        wigner_seitz_radius = 10.0
        spinless = False

        n_orbitals = grid_length**dimension
        if not spinless:
            n_orbitals *= 2
        n_particles = n_orbitals // 2

        length_scale = wigner_seitz_length_scale(wigner_seitz_radius,
                                                 n_particles, dimension)

        grid = Grid(dimension, grid_length, length_scale)
        hamiltonian = jellium_model(grid, spinless)
        hamiltonian_dual_basis = jellium_model(grid,
                                               spinless,
                                               plane_wave=False)

        # Get the Hamiltonians as sparse operators.
        hamiltonian_sparse = get_sparse_operator(hamiltonian)
        hamiltonian_dual_sparse = get_sparse_operator(hamiltonian_dual_basis)

        hf_state = hartree_fock_state_jellium(grid,
                                              n_particles,
                                              spinless,
                                              plane_wave=True)
        hf_state_dual = hartree_fock_state_jellium(grid,
                                                   n_particles,
                                                   spinless,
                                                   plane_wave=False)

        E_HF_plane_wave = expectation(hamiltonian_sparse, hf_state)
        E_HF_dual = expectation(hamiltonian_dual_sparse, hf_state_dual)

        self.assertAlmostEqual(E_HF_dual, E_HF_plane_wave)
Exemple #6
0
    def test_jw_restrict_jellium_ground_state_integration(self):
        n_qubits = 4
        grid = Grid(dimensions=1, length=n_qubits, scale=1.0)
        jellium_hamiltonian = jordan_wigner_sparse(
            jellium_model(grid, spinless=False))

        #  2 * n_qubits because of spin
        number_sparse = jordan_wigner_sparse(number_operator(2 * n_qubits))

        restricted_number = jw_number_restrict_operator(number_sparse, 2)
        restricted_jellium_hamiltonian = jw_number_restrict_operator(
            jellium_hamiltonian, 2)

        energy, ground_state = get_ground_state(restricted_jellium_hamiltonian)

        number_expectation = expectation(restricted_number, ground_state)
        self.assertAlmostEqual(number_expectation, 2)
Exemple #7
0
def hartree_fock_state_jellium(grid,
                               n_electrons,
                               spinless=True,
                               plane_wave=False):
    """Give the Hartree-Fock state of jellium.

    Args:
        grid (Grid): The discretization to use.
        n_electrons (int): Number of electrons in the system.
        spinless (bool): Whether to use the spinless model or not.
        plane_wave (bool): Whether to return the Hartree-Fock state in
                           the plane wave (True) or dual basis (False).

    Notes:
        The jellium model is built up by filling the lowest-energy
        single-particle states in the plane-wave Hamiltonian until
        n_electrons states are filled.
    """
    # Get the jellium Hamiltonian in the plane wave basis.
    hamiltonian = jellium_model(grid, spinless, plane_wave=True)
    hamiltonian = normal_ordered(hamiltonian)
    hamiltonian.compress()

    # Enumerate the single-particle states.
    n_single_particle_states = (grid.length**grid.dimensions)
    if not spinless:
        n_single_particle_states *= 2

    # Compute the energies for each of the single-particle states.
    single_particle_energies = numpy.zeros(n_single_particle_states,
                                           dtype=float)
    for i in range(n_single_particle_states):
        single_particle_energies[i] = hamiltonian.terms.get(((i, 1), (i, 0)),
                                                            0.0)

    # The number of occupied single-particle states is the number of electrons.
    # Those states with the lowest single-particle energies are occupied first.
    occupied_states = single_particle_energies.argsort()[:n_electrons]

    if plane_wave:
        # In the plane wave basis the HF state is a single determinant.
        hartree_fock_state_index = numpy.sum(2**occupied_states)
        hartree_fock_state = csr_matrix(
            ([1.0], ([hartree_fock_state_index], [0])),
            shape=(2**n_single_particle_states, 1))

    else:
        # Inverse Fourier transform the creation operators for the state to get
        # to the dual basis state, then use that to get the dual basis state.
        hartree_fock_state_creation_operator = FermionOperator.identity()
        for state in occupied_states[::-1]:
            hartree_fock_state_creation_operator *= (FermionOperator(
                ((int(state), 1), )))
        dual_basis_hf_creation_operator = inverse_fourier_transform(
            hartree_fock_state_creation_operator, grid, spinless)

        dual_basis_hf_creation = normal_ordered(
            dual_basis_hf_creation_operator)

        # Initialize the HF state as a sparse matrix.
        hartree_fock_state = csr_matrix(([], ([], [])),
                                        shape=(2**n_single_particle_states, 1),
                                        dtype=complex)

        # Populate the elements of the HF state in the dual basis.
        for term in dual_basis_hf_creation.terms:
            index = 0
            for operator in term:
                index += 2**operator[0]
            hartree_fock_state[index, 0] = dual_basis_hf_creation.terms[term]

    return hartree_fock_state
Exemple #8
0
 def test_jordan_wigner_dual_basis_hamiltonian_default_to_jellium(self):
     grid = Grid(dimensions=1, scale=1.0, length=4)
     self.assertTrue(
         jordan_wigner_dual_basis_hamiltonian(grid).isclose(
             jordan_wigner(jellium_model(grid, plane_wave=False))))
Exemple #9
0
 def test_plane_wave_hamiltonian_default_to_jellium_with_no_geometry(self):
     grid = Grid(dimensions=1, scale=1.0, length=4)
     self.assertTrue(
         plane_wave_hamiltonian(grid).isclose(jellium_model(grid)))