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_2body_adjacent_number_operator_1D(self): operator = FermionOperator('3^ 2^ 2 1') operator = normal_ordered(operator) transformed_operator = normal_ordered( fourier_transform(operator, self.grid1, self.spinless)) expected = expectation(get_sparse_operator(transformed_operator), self.hf_state1) actual = expectation_db_operator_with_pw_basis_state( operator, self.reversed_occupied_orbitals1, self.n_spatial_orbitals, self.grid1, self.spinless) self.assertAlmostEqual(expected, actual)
def operator_2d_fft_with_reordering(fermion_operator, system_size): """Apply the 2D FFT to an operator after reordering its modes. Args: fermion_operator (projectq.FermionOperator): Original operator. system_size (int): The side length of the system. register must thus have system_size ** 2 qubits. Notes: The reordering of the operators is the opposite of the ordering that would be applied to a state. This reordering is given in two stages. First, the bit-reversed output of the FFFT circuit (e.g. 0, 2, 1, 3 which is the four numbers 0, 1, 2, 3 after reversing their bit representations) is swapped to the standard order (e.g. 0, 1, 2, 3). Second, the standard order is swapped to the split-halves ordering used in fourier_transform (e.g. 2, 3, 0, 1 which swaps the left and right halves of that range). Both rounds must be applied before the FFFT, but after the FFFT only the second round needs to be undone so as to restore to the order of the FFFT circuit. All reorderings must be done in both dimensions, and because the operator is fermionic all swaps must also be. """ fermion_operator = normal_ordered(fermion_operator) grid = Grid(dimensions=2, length=system_size, scale=1.0) first_round_swaps, second_round_swaps = ffft_swap_networks(system_size, n_dimensions=2) # Create the full list of swaps. swap_mode_list = first_round_swaps + second_round_swaps swaps = [swap[0] for swap_layer in swap_mode_list for swap in swap_layer] # Swap adjacent modes for all swaps in both rounds. for mode in swaps: fermion_operator = swap_adjacent_fermionic_modes( fermion_operator, mode) fermion_operator = normal_ordered(fermion_operator) # Apply the Fourier transform to the reordered operator. fft_result = fourier_transform(fermion_operator, grid, spinless=True) fft_result = normal_ordered(fft_result) # Undo the second round of swaps to restore the FFT's bit-reversed order. swap_mode_list = second_round_swaps swaps = [swap[0] for swap_layer in swap_mode_list for swap in swap_layer] for mode in swaps: fft_result = swap_adjacent_fermionic_modes(fft_result, mode) fft_result = normal_ordered(fft_result) return fft_result
def test_8mode_ffft_with_external_swaps_on_single_logical_state(self): n_qubits = 8 grid = Grid(dimensions=1, length=n_qubits, scale=1.0) eng = MainEngine() register = eng.allocate_qureg(n_qubits) state_index = 157 prepare_logical_state(register, state_index) ffft(eng, register, n_qubits) Ph(3 * numpy.pi / 4) | register[0] eng.flush() wvfn = ordered_wavefunction(eng) fermion_operator = prepare_integer_fermion_operator(state_index) # 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: fermion_operator = normal_ordered(fermion_operator) fermion_operator = swap_adjacent_fermionic_modes( fermion_operator, mode) ffft_result = fourier_transform(fermion_operator, 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) converted_wvfn = numpy.zeros(2 ** n_qubits, dtype=complex) for term in ffft_result.terms: index = sum(2 ** site[0] for site in term) converted_wvfn[index] = ffft_result.terms[term] All(Measure) | register self.assertTrue(numpy.allclose(wvfn, converted_wvfn))
def test_4mode_ffft_with_external_swaps_all_logical_states(self): n_qubits = 4 grid = Grid(dimensions=1, length=n_qubits, scale=1.0) for i in range(2**n_qubits): eng = MainEngine() register = eng.allocate_qureg(n_qubits) prepare_logical_state(register, i) ffft(eng, register, n_qubits) Ph(3 * numpy.pi / 4) | register[0] eng.flush() wvfn = ordered_wavefunction(eng) fermion_operator = prepare_integer_fermion_operator(i) # Reorder the modes for correct input to the FFFT. # Swap 0123 to 2301 for fourier_transform. Additionally, the # FFFT's ordering is 0213, so connect 0213 -> 0123 -> 2301. swap_mode_list = [1] + [1, 0, 2, 1] for mode in swap_mode_list: fermion_operator = normal_ordered(fermion_operator) fermion_operator = swap_adjacent_fermionic_modes( fermion_operator, mode) ffft_result = fourier_transform(fermion_operator, grid, spinless=True) ffft_result = normal_ordered(ffft_result) swap_mode_list = [1, 0, 2, 1] # After FFFT, swap 2301 -> 0123 for mode in swap_mode_list: ffft_result = swap_adjacent_fermionic_modes(ffft_result, mode) converted_wvfn = numpy.zeros(2**n_qubits, dtype=complex) for term in ffft_result.terms: index = sum(2**site[0] for site in term) converted_wvfn[index] = ffft_result.terms[term] All(Measure) | register self.assertTrue(numpy.allclose(wvfn, converted_wvfn))
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)