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)
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)
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()))
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)
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)
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
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)
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)
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))
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))
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)
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
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))
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())
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)