def expectation_one_body_db_operator_computational_basis_state( dual_basis_action, plane_wave_occ_orbitals, grid, spinless): """Compute expectation value of a 1-body dual-basis operator with a plane wave computational basis state. Args: dual_basis_action: Dual-basis action of FermionOperator to evaluate expectation value of. plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals. grid (openfermion.utils.Grid): The grid used for discretization. spinless (bool): Whether the system is spinless. Returns: A real float giving the expectation value. """ expectation_value = 0.0 r_p = position_vector(grid_indices(dual_basis_action[0][0], grid, spinless), grid) r_q = position_vector(grid_indices(dual_basis_action[1][0], grid, spinless), grid) for orbital in plane_wave_occ_orbitals: # If there's spin, p and q have to have the same parity (spin), # and the new orbital has to have the same spin as these. k_orbital = momentum_vector(grid_indices(orbital, grid, spinless), grid) # The Fourier transform is spin-conserving. This means that p, q, # and the new orbital all have to have the same spin (parity). if spinless or (dual_basis_action[0][0] % 2 == dual_basis_action[1][0] % 2 == orbital % 2): expectation_value += numpy.exp(-1j * k_orbital.dot(r_p - r_q)) return expectation_value
def jordan_wigner_dual_basis_hamiltonian(grid, geometry=None, spinless=False, include_constant=False): """Return the dual basis Hamiltonian as QubitOperator. Args: grid (Grid): The discretization to use. geometry: A list of tuples giving the coordinates of each atom. example is [('H', (0, 0, 0)), ('H', (0, 0, 0.7414))]. Distances in atomic units. Use atomic symbols to specify atoms. spinless (bool): Whether to use the spinless model or not. include_constant (bool): Whether to include the Madelung constant. Returns: hamiltonian (QubitOperator) """ jellium_op = jordan_wigner_dual_basis_jellium(grid, spinless, include_constant) if geometry is None: return jellium_op for item in geometry: if len(item[1]) != grid.dimensions: raise ValueError("Invalid geometry coordinate.") if item[0] not in periodic_hash_table: raise ValueError("Invalid nuclear element.") n_orbitals = grid.num_points() volume = grid.volume_scale() if spinless: n_qubits = n_orbitals else: n_qubits = 2 * n_orbitals prefactor = -2 * numpy.pi / volume external_potential = QubitOperator() for k_indices in grid.all_points_indices(): momenta = momentum_vector(k_indices, grid) momenta_squared = momenta.dot(momenta) if momenta_squared < EQ_TOLERANCE: continue for p in range(n_qubits): index_p = grid_indices(p, grid, spinless) coordinate_p = position_vector(index_p, grid) for nuclear_term in geometry: coordinate_j = numpy.array(nuclear_term[1], float) exp_index = 1.0j * momenta.dot(coordinate_j - coordinate_p) coefficient = (prefactor / momenta_squared * periodic_hash_table[nuclear_term[0]] * numpy.exp(exp_index)) external_potential += (QubitOperator( (), coefficient) - QubitOperator( ((p, 'Z'), ), coefficient)) return jellium_op + external_potential
def _fourier_transform_helper(hamiltonian, grid, spinless, phase_factor, vec_func_1, vec_func_2): hamiltonian_t = FermionOperator.zero() normalize_factor = numpy.sqrt(1.0 / float(grid.num_points())) for term in hamiltonian.terms: transformed_term = FermionOperator.identity() for ladder_op_mode, ladder_op_type in term: indices_1 = grid_indices(ladder_op_mode, grid, spinless) vec1 = vec_func_1(indices_1, grid) new_basis = FermionOperator.zero() for indices_2 in grid.all_points_indices(): vec2 = vec_func_2(indices_2, grid) spin = None if spinless else ladder_op_mode % 2 orbital = orbital_id(grid, indices_2, spin) exp_index = phase_factor * 1.0j * numpy.dot(vec1, vec2) if ladder_op_type == 1: exp_index *= -1.0 element = FermionOperator(((orbital, ladder_op_type), ), numpy.exp(exp_index)) new_basis += element new_basis *= normalize_factor transformed_term *= new_basis # Coefficient. transformed_term *= hamiltonian.terms[term] hamiltonian_t += transformed_term return hamiltonian_t
def expectation_three_body_db_operator_computational_basis_state( dual_basis_action, plane_wave_occ_orbitals, grid, spinless): """Compute expectation value of a 3-body dual-basis operator with a plane wave computational basis state. Args: dual_basis_action: Dual-basis action of FermionOperator to evaluate expectation value of. plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals. grid (openfermion.utils.Grid): The grid used for discretization. spinless (bool): Whether the system is spinless. Returns: A float giving the expectation value. """ expectation_value = 0.0 r = {} for i in range(6): r[i] = position_vector(grid_indices(dual_basis_action[i][0], grid, spinless), grid) rr = {} k_map = {} for i in range(3): rr[i] = {} k_map[i] = {} for j in range(3, 6): rr[i][j] = r[i] - r[j] k_map[i][j] = {} # Pre-computations. for o in plane_wave_occ_orbitals: k = momentum_vector(grid_indices(o, grid, spinless), grid) for i in range(3): for j in range(3, 6): k_map[i][j][o] = k.dot(rr[i][j]) for orbital1 in plane_wave_occ_orbitals: k1ad = k_map[0][3][orbital1] k1ae = k_map[0][4][orbital1] k1af = k_map[0][5][orbital1] for orbital2 in plane_wave_occ_orbitals: if orbital1 != orbital2: k2bd = k_map[1][3][orbital2] k2be = k_map[1][4][orbital2] k2bf = k_map[1][5][orbital2] for orbital3 in plane_wave_occ_orbitals: if orbital1 != orbital3 and orbital2 != orbital3: k3cd = k_map[2][3][orbital3] k3ce = k_map[2][4][orbital3] k3cf = k_map[2][5][orbital3] # Handle \delta_{ad} \delta_{bf} \delta_{ce} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[3][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[5][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[4][0] % 2 == orbital3 % 2)): expectation_value += numpy.exp(-1j * ( k1ad + k2bf + k3ce)) # Handle -\delta_{ad} \delta_{be} \delta_{cf} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[3][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[4][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[5][0] % 2 == orbital3 % 2)): expectation_value -= numpy.exp(-1j * ( k1ad + k2be + k3cf)) # Handle -\delta_{ae} \delta_{bf} \delta_{cd} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[4][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[5][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[3][0] % 2 == orbital3 % 2)): expectation_value -= numpy.exp(-1j * ( k1ae + k2bf + k3cd)) # Handle \delta_{ae} \delta_{bd} \delta_{cf} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[4][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[3][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[5][0] % 2 == orbital3 % 2)): expectation_value += numpy.exp(-1j * ( k1ae + k2bd + k3cf)) # Handle \delta_{af} \delta_{be} \delta_{cd} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[5][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[4][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[3][0] % 2 == orbital3 % 2)): expectation_value += numpy.exp(-1j * ( k1af + k2be + k3cd)) # Handle -\delta_{af} \delta_{bd} \delta_{ce} after FT. # The Fourier transform is spin-conserving. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[5][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[3][0] % 2 == orbital2 % 2) and (dual_basis_action[2][0] % 2 == dual_basis_action[4][0] % 2 == orbital3 % 2)): expectation_value -= numpy.exp(-1j * ( k1af + k2bd + k3ce)) return expectation_value
def expectation_two_body_db_operator_computational_basis_state( dual_basis_action, plane_wave_occ_orbitals, grid, spinless): """Compute expectation value of a 2-body dual-basis operator with a plane wave computational basis state. Args: dual_basis_action: Dual-basis action of FermionOperator to evaluate expectation value of. plane_wave_occ_orbitals (list): list of occupied plane-wave orbitals. grid (openfermion.utils.Grid): The grid used for discretization. spinless (bool): Whether the system is spinless. Returns: A float giving the expectation value. """ expectation_value = 0.0 r = {} for i in range(4): r[i] = position_vector(grid_indices(dual_basis_action[i][0], grid, spinless), grid) rr = {} k_map = {} for i in range(2): rr[i] = {} k_map[i] = {} for j in range(2, 4): rr[i][j] = r[i] - r[j] k_map[i][j] = {} # Pre-computations. for o in plane_wave_occ_orbitals: k = momentum_vector(grid_indices(o, grid, spinless), grid) for i in range(2): for j in range(2, 4): k_map[i][j][o] = k.dot(rr[i][j]) for orbital1 in plane_wave_occ_orbitals: k1ac = k_map[0][2][orbital1] k1ad = k_map[0][3][orbital1] for orbital2 in plane_wave_occ_orbitals: if orbital1 != orbital2: k2bc = k_map[1][2][orbital2] k2bd = k_map[1][3][orbital2] # The Fourier transform is spin-conserving. This means that # the parity of the orbitals involved in the transition must # be the same. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[3][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[2][0] % 2 == orbital2 % 2)): value = numpy.exp(-1j * (k1ad + k2bc)) # Add because it came from two anti-commutations. expectation_value += value # The Fourier transform is spin-conserving. This means that # the parity of the orbitals involved in the transition must # be the same. if spinless or ( (dual_basis_action[0][0] % 2 == dual_basis_action[2][0] % 2 == orbital1 % 2) and (dual_basis_action[1][0] % 2 == dual_basis_action[3][0] % 2 == orbital2 % 2)): value = numpy.exp(-1j * (k1ac + k2bd)) # Subtract because it came from a single anti-commutation. expectation_value -= value return expectation_value