Example #1
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
        n_particles = n_qubits // inverse_filling_fraction

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius,
            1. / inverse_filling_fraction)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        terms = simulation_ordered_grouped_low_depth_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 == hamiltonian)
    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)
Example #3
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 = standardized_dual_basis_jellium_hamiltonian(
            grid_length, dimension, wigner_seitz_radius, n_particles)

        terms = simulation_ordered_grouped_low_depth_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 == hamiltonian)
Example #4
0
    def test_integration_jellium_hamiltonian_with_negation(self):
        hamiltonian = normal_ordered(
            jellium_model(Grid(2, 3, 1.), plane_wave=False))

        part_a = FermionOperator.zero()
        part_b = FermionOperator.zero()

        add_to_a_or_b = 0  # add to a if 0; add to b if 1
        for term, coeff in hamiltonian.terms.items():
            # Partition terms in the Hamiltonian into part_a or part_b
            if add_to_a_or_b:
                part_a += FermionOperator(term, coeff)
            else:
                part_b += FermionOperator(term, coeff)
            add_to_a_or_b ^= 1

        reference = normal_ordered(commutator(part_a, part_b))
        result = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            part_a, part_b)

        self.assertTrue(result.isclose(reference))

        negative = commutator_ordered_diagonal_coulomb_with_two_body_operator(
            part_b, part_a)
        result += negative

        self.assertTrue(result.isclose(FermionOperator.zero()))
Example #5
0
    def test_correct_indices_terms_with_info(self):
        grid_length = 4
        dimension = 1
        wigner_seitz_radius = 10.0
        inverse_filling_fraction = 2
        n_qubits = grid_length**dimension

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius,
            1. / inverse_filling_fraction)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        # Unpack result into terms, indices they act on, and whether they're
        # hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian)
        terms, indices, is_hopping = result

        for i in range(len(terms)):
            term = list(terms[i].terms)
            term_indices = set()
            for single_term in term:
                term_indices = term_indices.union(
                    [single_term[j][0] for j in range(len(single_term))])
            self.assertEqual(term_indices, indices[i])
    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)
    def test_3d2_with_spin(self):
        dimension = 3
        grid_length = 2
        n_spatial_orbitals = grid_length**dimension
        wigner_seitz_radius = 9.3

        spinless = False
        n_qubits = n_spatial_orbitals
        if not spinless:
            n_qubits *= 2
        n_particles_big = 9

        length_scale = wigner_seitz_length_scale(wigner_seitz_radius,
                                                 n_particles_big, dimension)

        self.grid3 = Grid(dimension, grid_length, length_scale)
        # Get the occupied orbitals of the plane-wave basis Hartree-Fock state.
        hamiltonian = jellium_model(self.grid3, spinless, plane_wave=True)
        hamiltonian = normal_ordered(hamiltonian)
        hamiltonian.compress()

        occupied_states = numpy.array(
            lowest_single_particle_energy_states(hamiltonian, n_particles_big))
        self.hf_state_index3 = numpy.sum(2**occupied_states)

        self.hf_state3 = csc_matrix(([1.0], ([self.hf_state_index3], [0])),
                                    shape=(2**n_qubits, 1))

        self.orbital_occupations3 = [
            digit == '1' for digit in bin(self.hf_state_index3)[2:]
        ][::-1]
        self.occupied_orbitals3 = [
            index for index, occupied in enumerate(self.orbital_occupations3)
            if occupied
        ]

        self.reversed_occupied_orbitals3 = list(self.occupied_orbitals3)
        for i in range(len(self.reversed_occupied_orbitals3)):
            self.reversed_occupied_orbitals3[i] = -1 + int(
                numpy.log2(self.hf_state3.shape[0])
            ) - self.reversed_occupied_orbitals3[i]

        self.reversed_hf_state_index3 = sum(
            2**index for index in self.reversed_occupied_orbitals3)

        operator = (FermionOperator('4^ 2^ 3^ 5 5 4', 2) +
                    FermionOperator('7^ 6^ 7 4', -3.7j) +
                    FermionOperator('3^ 7', 2.1))
        operator = normal_ordered(operator)
        transformed_operator = normal_ordered(
            fourier_transform(operator, self.grid3, spinless))

        expected = -0.2625 - 0.578125j
        # Calculated from expected = expectation(get_sparse_operator(
        #    transformed_operator), self.hf_state3)
        actual = expectation_db_operator_with_pw_basis_state(
            operator, self.reversed_occupied_orbitals3, n_spatial_orbitals,
            self.grid3, spinless)

        self.assertAlmostEqual(expected, actual)
Example #8
0
    def test_jellium_hamiltonian_correctly_broken_up(self):
        grid = Grid(2, 3, 1.)

        hamiltonian = jellium_model(grid, spinless=True, plane_wave=False)

        potential_terms, kinetic_terms = (
            diagonal_coulomb_potential_and_kinetic_terms_as_arrays(hamiltonian)
        )

        potential = sum(potential_terms, FermionOperator.zero())
        kinetic = sum(kinetic_terms, FermionOperator.zero())

        true_potential = dual_basis_jellium_model(grid,
                                                  spinless=True,
                                                  kinetic=False)
        true_kinetic = dual_basis_jellium_model(grid,
                                                spinless=True,
                                                potential=False)
        for i in range(count_qubits(true_kinetic)):
            coeff = true_kinetic.terms.get(((i, 1), (i, 0)))
            if coeff:
                true_kinetic -= FermionOperator(((i, 1), (i, 0)), coeff)
                true_potential += FermionOperator(((i, 1), (i, 0)), coeff)

        self.assertEqual(potential, true_potential)
        self.assertEqual(kinetic, true_kinetic)
Example #9
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
Example #10
0
    def test_is_hopping_operator_terms_with_info(self):
        grid_length = 4
        dimension = 1
        wigner_seitz_radius = 10.0
        inverse_filling_fraction = 2

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius,
            1. / inverse_filling_fraction)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        # Unpack result into terms, indices they act on, and whether they're
        # hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian)
        terms, indices, is_hopping = result

        for i in range(len(terms)):
            single_term = list(terms[i].terms)[0]
            is_hopping_term = not (single_term[1][1]
                                   or single_term[0][0] == single_term[1][0])
            self.assertEqual(is_hopping_term, is_hopping[i])
    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 = numpy.zeros(2**grid_length)
            HF_competitor[state_index] = 1.0

            self.assertLessEqual(HF_energy,
                                 expectation(hamiltonian_sparse, HF_competitor))
    def test_ffft_2d_4x4_equal_expectation_values(self):
        system_size = 4
        n_qubits = 16
        grid = Grid(dimensions=2, length=system_size, scale=1.0)
        dual_basis = jellium_model(grid, spinless=True, plane_wave=False)
        ffft_result = operator_2d_fft_with_reordering(dual_basis, system_size)

        jw_dual_basis = jordan_wigner(dual_basis)
        jw_plane_wave = jordan_wigner(ffft_result)

        # Do plane wave and dual basis calculations together.
        pw_engine = MainEngine()
        pw_wavefunction = pw_engine.allocate_qureg(system_size ** 2)
        db_engine = MainEngine()
        db_wavefunction = db_engine.allocate_qureg(system_size ** 2)

        pw_engine.flush()
        db_engine.flush()

        # Choose random state.
        state = numpy.zeros(2 ** n_qubits, dtype=complex)
        for i in range(len(state)):
            state[i] = (random.random() *
                        numpy.exp(1j * 2 * numpy.pi * random.random()))
        state /= numpy.linalg.norm(state)

        # Put randomly chosen state in the registers.
        pw_engine.backend.set_wavefunction(state, pw_wavefunction)
        db_engine.backend.set_wavefunction(state, db_wavefunction)

        # Apply the FFFT to the dual basis wave function.
        ffft_2d(db_engine, db_wavefunction, system_size)

        # Flush the engine and compute expectation values and eigenvalues.
        pw_engine.flush()
        db_engine.flush()

        plane_wave_expectation_value = (
            pw_engine.backend.get_expectation_value(
                jw_dual_basis, pw_wavefunction))
        dual_basis_expectation_value = (
            db_engine.backend.get_expectation_value(
                jw_plane_wave, db_wavefunction))

        All(Measure) | pw_wavefunction
        All(Measure) | db_wavefunction

        self.assertAlmostEqual(plane_wave_expectation_value,
                               dual_basis_expectation_value)
Example #13
0
    def test_sum_of_ordered_terms_equals_full_hamiltonian(self):
        grid_length = 4
        dimension = 1
        wigner_seitz_radius = 10.0

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        terms = ordered_low_depth_terms_no_info(hamiltonian)
        terms_total = sum(terms, FermionOperator.zero())

        self.assertTrue(terms_total == hamiltonian)
Example #14
0
    def test_abstract_molecule(self):
        """Test an abstract molecule like jellium for saving and loading"""
        jellium_interaction = get_interaction_operator(
            jellium_model(Grid(2, 2, 1.0)))
        jellium_molecule = get_molecular_data(jellium_interaction,
                                              geometry="Jellium",
                                              basis="PlaneWave22",
                                              multiplicity=1,
                                              n_electrons=4)

        jellium_filename = jellium_molecule.filename
        jellium_molecule.save()
        jellium_molecule.load()
        correct_name = "Jellium_PlaneWave22_singlet"
        self.assertEqual(jellium_molecule.name, correct_name)
        os.remove("{}.hdf5".format(jellium_filename))
Example #15
0
    def test_all_terms_in_standardized_dual_basis_jellium_hamiltonian(self):
        grid_length = 4
        dimension = 1

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius=10.)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        terms = ordered_low_depth_terms_no_info(hamiltonian)
        FO = FermionOperator

        expected_terms = []
        for i in range(grid_length**dimension):
            expected_terms.append(FO(((i, 1), (i, 0)), 0.018505508252042547))
            expected_terms.append(
                FO(((i, 1), ((i + 1) % 4, 0)), -0.012337005501361697))
            expected_terms.append(
                FO(((i, 1), ((i + 2) % 4, 0)), 0.0061685027506808475))
            expected_terms.append(
                FO(((i, 1), ((i + 3) % 4, 0)), -0.012337005501361697))
            expected_terms.append(
                normal_ordered(
                    FO(((i, 1), ((i + 1) % 4, 1), (i, 0), ((i + 1) % 4, 0)),
                       3.1830988618379052)))
            if i // 2:
                expected_terms.append(
                    normal_ordered(
                        FO(((i, 1), ((i + 2) % 4, 1), (i, 0),
                            ((i + 2) % 4, 0)), 22.281692032865351)))

        for term in terms:
            found_in_other = False
            for term2 in expected_terms:
                if term == term2:
                    self.assertFalse(found_in_other)
                    found_in_other = True
            self.assertTrue(found_in_other, msg=str(term))
        for term in expected_terms:
            found_in_other = False
            for term2 in terms:
                if term == term2:
                    self.assertFalse(found_in_other)
                    found_in_other = True
            self.assertTrue(found_in_other, msg=str(term))
Example #16
0
    def test_error_bound_using_info_1d_with_input_ordering(self):
        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension=1, grid_length=4, wigner_seitz_radius=10.)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        # Unpack result into terms, indices they act on, and whether they're
        # hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian, input_ordering=[0, 1, 2, 3])
        terms, indices, is_hopping = result
        self.assertAlmostEqual(
            low_depth_second_order_trotter_error_bound(terms, indices,
                                                       is_hopping),
            7.4239378440953283)
    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)
    def setUp(self):
        grid_length = 4
        dimension = 1
        wigner_seitz_radius = 10.
        self.spinless = True
        self.n_spatial_orbitals = grid_length**dimension

        n_qubits = self.n_spatial_orbitals
        self.n_particles = 3

        # Compute appropriate length scale and the corresponding grid.
        length_scale = wigner_seitz_length_scale(wigner_seitz_radius,
                                                 self.n_particles, dimension)

        self.grid1 = Grid(dimension, grid_length, length_scale)
        # Get the occupied orbitals of the plane-wave basis Hartree-Fock state.
        hamiltonian = jellium_model(self.grid1, self.spinless, plane_wave=True)
        hamiltonian = normal_ordered(hamiltonian)
        hamiltonian.compress()

        occupied_states = numpy.array(
            lowest_single_particle_energy_states(hamiltonian,
                                                 self.n_particles))
        self.hf_state_index1 = numpy.sum(2**occupied_states)

        self.hf_state1 = csc_matrix(([1.0], ([self.hf_state_index1], [0])),
                                    shape=(2**n_qubits, 1))

        self.orbital_occupations1 = [
            digit == '1' for digit in bin(self.hf_state_index1)[2:]
        ][::-1]
        self.occupied_orbitals1 = [
            index for index, occupied in enumerate(self.orbital_occupations1)
            if occupied
        ]

        self.reversed_occupied_orbitals1 = list(self.occupied_orbitals1)
        for i in range(len(self.reversed_occupied_orbitals1)):
            self.reversed_occupied_orbitals1[i] = -1 + int(
                numpy.log2(self.hf_state1.shape[0])
            ) - self.reversed_occupied_orbitals1[i]

        self.reversed_hf_state_index1 = sum(
            2**index for index in self.reversed_occupied_orbitals1)
Example #19
0
    def test_1d_jellium_wigner_seitz_10_VT_order_gives_larger_error(self):
        hamiltonian = normal_ordered(jellium_model(
            hypercube_grid_with_given_wigner_seitz_radius_and_filling(
                1, 5, wigner_seitz_radius=10.,
                spinless=True), spinless=True, plane_wave=False))

        TV_error_operator = (
            split_operator_trotter_error_operator_diagonal_two_body(
                hamiltonian, order='T+V'))
        TV_error_bound = numpy.sum(numpy.absolute(
            list(TV_error_operator.terms.values())))

        VT_error_operator = (
            split_operator_trotter_error_operator_diagonal_two_body(
                hamiltonian, order='V+T'))
        VT_error_bound = numpy.sum(numpy.absolute(
            list(VT_error_operator.terms.values())))

        self.assertGreater(VT_error_bound, TV_error_bound)
def benchmark_commutator_diagonal_coulomb_operators_2D_spinless_jellium(
        side_length):
    """Test speed of computing commutators using specialized functions.

    Args:
        side_length: The side length of the 2D jellium grid. There are
            side_length ** 2 qubits, and O(side_length ** 4) terms in the
            Hamiltonian.

    Returns:
        runtime_commutator: The time it takes to compute a commutator, after
            partitioning the terms and normal ordering, using the regular
            commutator function.
        runtime_diagonal_commutator: The time it takes to compute the same
            commutator using methods restricted to diagonal Coulomb operators.
    """
    hamiltonian = normal_ordered(
        jellium_model(Grid(2, side_length, 1.), plane_wave=False))

    part_a = FermionOperator.zero()
    part_b = FermionOperator.zero()
    add_to_a_or_b = 0  # add to a if 0; add to b if 1
    for term, coeff in hamiltonian.terms.items():
        # Partition terms in the Hamiltonian into part_a or part_b
        if add_to_a_or_b:
            part_a += FermionOperator(term, coeff)
        else:
            part_b += FermionOperator(term, coeff)
        add_to_a_or_b ^= 1

    start = time.time()
    _ = normal_ordered(commutator(part_a, part_b))
    end = time.time()
    runtime_commutator = end - start

    start = time.time()
    _ = commutator_ordered_diagonal_coulomb_with_two_body_operator(
        part_a, part_b)
    end = time.time()
    runtime_diagonal_commutator = end - start

    return runtime_commutator, runtime_diagonal_commutator
Example #21
0
    def test_error_bound_using_info_2d_verbose(self):
        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension=2, grid_length=3, wigner_seitz_radius=10.)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        # Unpack result into terms, indices they act on, and whether they're
        # hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian)
        terms, indices, is_hopping = result
        self.assertAlmostEqual(
            low_depth_second_order_trotter_error_bound(terms,
                                                       indices,
                                                       is_hopping,
                                                       jellium_only=True,
                                                       verbose=True),
            0.052213321121580794)
    def test_sum_of_ordered_terms_equals_full_hamiltonian(self):
        grid_length = 4
        dimension = 1
        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
        length_scale = wigner_seitz_length_scale(
            wigner_seitz_radius, n_particles, dimension)

        hamiltonian = dual_basis_jellium_hamiltonian(grid_length, dimension)
        terms = ordered_dual_basis_terms_no_info(hamiltonian)
        terms_total = sum(terms, FermionOperator.zero())

        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))
Example #23
0
    def test_1D_jellium_trotter_error_matches_low_depth_trotter_error(self):
        hamiltonian = normal_ordered(jellium_model(
            hypercube_grid_with_given_wigner_seitz_radius_and_filling(
                1, 5, wigner_seitz_radius=10.,
                spinless=True), spinless=True, plane_wave=False))

        error_operator = (
            fermionic_swap_trotter_error_operator_diagonal_two_body(
                hamiltonian))
        error_operator.compress()

        # Unpack result into terms, indices they act on, and whether
        # they're hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian)
        terms, indices, is_hopping = result

        old_error_operator = low_depth_second_order_trotter_error_operator(
            terms, indices, is_hopping, jellium_only=True)

        old_error_operator -= error_operator
        self.assertEqual(old_error_operator, FermionOperator.zero())
Example #24
0
    def test_total_length(self):
        grid_length = 8
        dimension = 1
        wigner_seitz_radius = 10.0
        inverse_filling_fraction = 2
        n_qubits = grid_length**dimension

        # Generate the Hamiltonian.
        grid = hypercube_grid_with_given_wigner_seitz_radius_and_filling(
            dimension, grid_length, wigner_seitz_radius,
            1. / inverse_filling_fraction)
        hamiltonian = normal_ordered(
            jellium_model(grid, spinless=True, plane_wave=False))
        hamiltonian.compress()

        # Unpack result into terms, indices they act on, and whether they're
        # hopping operators.
        result = simulation_ordered_grouped_low_depth_terms_with_info(
            hamiltonian)
        terms, indices, is_hopping = result

        self.assertEqual(len(terms), n_qubits * (n_qubits - 1))
 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) == jordan_wigner(
             jellium_model(grid, plane_wave=False)))
 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) == jellium_model(grid))
    def test_8mode_ffft_with_external_swaps_equal_expectation_values(self):
        n_qubits = 8

        grid = Grid(dimensions=1, length=n_qubits, scale=1.0)
        dual_basis = jellium_model(grid, spinless=True, plane_wave=False)
        ffft_result = normal_ordered(dual_basis)

        # Swap 01234567 to 45670123 for fourier_transform. Additionally,
        # the FFFT's ordering is 04261537, so swap 04261537 to 01234567,
        # and then 01234567 to 45670123.
        swap_mode_list = ([1, 3, 5, 2, 4, 1, 3, 5] +
                          [3, 2, 4, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 2, 4, 3])
        for mode in swap_mode_list:
            ffft_result = swap_adjacent_fermionic_modes(ffft_result, mode)
            ffft_result = normal_ordered(ffft_result)

        ffft_result = fourier_transform(ffft_result,
                                        grid, spinless=True)
        ffft_result = normal_ordered(ffft_result)

        # After the FFFT, swap 45670123 -> 01234567.
        swap_mode_list = [3, 2, 4, 1, 3, 5, 0, 2, 4, 6, 1, 3, 5, 2, 4, 3]
        for mode in swap_mode_list:
            ffft_result = swap_adjacent_fermionic_modes(ffft_result, mode)
            ffft_result = normal_ordered(ffft_result)

        jw_dual_basis = jordan_wigner(dual_basis)
        jw_plane_wave = jordan_wigner(ffft_result)

        # Do plane wave and dual basis calculations simultaneously.
        pw_engine = MainEngine()
        pw_wavefunction = pw_engine.allocate_qureg(n_qubits)
        db_engine = MainEngine()
        db_wavefunction = db_engine.allocate_qureg(n_qubits)

        pw_engine.flush()
        db_engine.flush()

        # Choose random state.
        state = numpy.zeros(2 ** n_qubits, dtype=complex)
        for i in range(len(state)):
            state[i] = (random.random() *
                        numpy.exp(1j * 2 * numpy.pi * random.random()))
        state /= numpy.linalg.norm(state)

        # Put randomly chosen state in the registers.
        pw_engine.backend.set_wavefunction(state, pw_wavefunction)
        db_engine.backend.set_wavefunction(state, db_wavefunction)

        prepare_logical_state(pw_wavefunction, i)
        prepare_logical_state(db_wavefunction, i)

        All(H) | [pw_wavefunction[1], pw_wavefunction[3]]
        All(H) | [db_wavefunction[1], db_wavefunction[3]]

        ffft(db_engine, db_wavefunction, n_qubits)
        Ph(3 * numpy.pi / 4) | db_wavefunction[0]

        # Flush the engine and compute expectation values and eigenvalues.
        pw_engine.flush()
        db_engine.flush()

        plane_wave_expectation_value = (
            pw_engine.backend.get_expectation_value(
                jw_dual_basis, pw_wavefunction))
        dual_basis_expectation_value = (
            db_engine.backend.get_expectation_value(
                jw_plane_wave, db_wavefunction))

        All(Measure) | pw_wavefunction
        All(Measure) | db_wavefunction

        self.assertAlmostEqual(plane_wave_expectation_value,
                               dual_basis_expectation_value)