def process_fermi_hubbard_hopping(constituents): for c in constituents: if c in ['down', 'up']: spin_type = c elif c[0] == 'd': num_sites = int(c[1:]) else: sites = [int(s) for s in c.split('h')] i_idx = 2 * (sites[0] - 1) - 2 # 2i -2 j_idx = 2 * (sites[1] - 1) - 2 # 2j -2 if spin_type == 'down': i_idx = 2 * (sites[0] - 1) j_idx = 2 * (sites[1] - 1) elif spin_type == 'up': i_idx = 2 * (sites[0]) - 1 j_idx = 2 * (sites[1]) - 1 dimensional_description = "{}".format(2 * num_sites - 1) dimensional_fermion_op = FermionOperator(dimensional_description) hopping_term = FermionOperator(((i_idx, 1), (j_idx, 0))) hopping_term += FermionOperator(((j_idx, 1), (i_idx, 0))) hopping_term += dimensional_fermion_op mtx = jordan_wigner_mtx(hopping_term) - \ jordan_wigner_mtx(dimensional_fermion_op) return np.array(mtx)
def test_jw_restrict_operator_hopping_to_1_particle(self): hop = FermionOperator('3^ 1') + FermionOperator('1^ 3') hop_sparse = jordan_wigner_sparse(hop, n_qubits=4) hop_restrict = jw_number_restrict_operator(hop_sparse, 1, n_qubits=4) expected = csc_matrix(([1, 1], ([0, 2], [2, 0])), shape=(4, 4)) self.assertTrue(numpy.allclose(hop_restrict.A, expected.A))
def test_bravyi_kitaev_transform(self): # Check that the QubitOperators are two-term. lowering = bravyi_kitaev(FermionOperator(((3, 0), ))) raising = bravyi_kitaev(FermionOperator(((3, 1), ))) self.assertEqual(len(raising.terms), 2) self.assertEqual(len(lowering.terms), 2) # Test the locality invariant for N=2^d qubits # (c_j majorana is always log2N+1 local on qubits) n_qubits = 16 invariant = numpy.log2(n_qubits) + 1 for index in range(n_qubits): operator = bravyi_kitaev(FermionOperator(((index, 0), )), n_qubits) qubit_terms = operator.terms.items() # Get the majorana terms. for item in qubit_terms: coeff = item[1] # Identify the c majorana terms by real # coefficients and check their length. if not isinstance(coeff, complex): self.assertEqual(len(item[0]), invariant) # Hardcoded coefficient test on 16 qubits lowering = bravyi_kitaev(FermionOperator(((9, 0), )), n_qubits) raising = bravyi_kitaev(FermionOperator(((9, 1), )), n_qubits) correct_operators_c = ((7, 'Z'), (8, 'Z'), (9, 'X'), (11, 'X'), (15, 'X')) correct_operators_d = ((7, 'Z'), (9, 'Y'), (11, 'X'), (15, 'X')) self.assertEqual(lowering.terms[correct_operators_c], 0.5) self.assertEqual(lowering.terms[correct_operators_d], 0.5j) self.assertEqual(raising.terms[correct_operators_d], -0.5j) self.assertEqual(raising.terms[correct_operators_c], 0.5)
def position_potential_operator(n_dimensions, grid_length, length_scale, spinless=False): """Return the potential operator in position space second quantization. Args: n_dimensions: An int giving the number of dimensions for the model. grid_length: Int, the number of points in one dimension of the grid. length_scale: Float, the real space length of a box dimension. spinless: Boole, whether to use the spinless model or not. Returns: operator: An instance of the FermionOperator class. """ # Initialize. n_points = grid_length**n_dimensions volume = length_scale**float(n_dimensions) prefactor = 2. * numpy.pi / volume operator = FermionOperator() if spinless: spins = [None] else: spins = [0, 1] # Loop once through all lattice sites. for grid_indices_a in itertools.product(range(grid_length), repeat=n_dimensions): coordinates_a = position_vector(grid_indices_a, grid_length, length_scale) for grid_indices_b in itertools.product(range(grid_length), repeat=n_dimensions): coordinates_b = position_vector(grid_indices_b, grid_length, length_scale) differences = coordinates_b - coordinates_a # Compute coefficient. coefficient = 0. for momenta_indices in itertools.product(range(grid_length), repeat=n_dimensions): momenta = momentum_vector(momenta_indices, grid_length, length_scale) if momenta.any(): coefficient += (prefactor * numpy.cos(momenta.dot(differences)) / momenta.dot(momenta)) # Loop over spins and identify interacting orbitals. for spin_a in spins: orbital_a = orbital_id(grid_length, grid_indices_a, spin_a) for spin_b in spins: orbital_b = orbital_id(grid_length, grid_indices_b, spin_b) # Add interaction term. if orbital_a != orbital_b: operators = ((orbital_a, 1), (orbital_a, 0), (orbital_b, 1), (orbital_b, 0)) operator += FermionOperator(operators, coefficient) return operator
def test_bk_jw_majoranas(self): # Check if the Majorana operators have the same spectrum # irrespectively of the transform. n_qubits = 7 a = FermionOperator(((1, 0), )) a_dag = FermionOperator(((1, 1), )) c = a + a_dag d = 1j * (a_dag - a) c_spins = [jordan_wigner(c), bravyi_kitaev(c)] d_spins = [jordan_wigner(d), bravyi_kitaev(d)] c_sparse = [ get_sparse_operator(c_spins[0]), get_sparse_operator(c_spins[1]) ] d_sparse = [ get_sparse_operator(d_spins[0]), get_sparse_operator(d_spins[1]) ] c_spectrum = [eigenspectrum(c_spins[0]), eigenspectrum(c_spins[1])] d_spectrum = [eigenspectrum(d_spins[0]), eigenspectrum(d_spins[1])] self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(d_spectrum[0] - d_spectrum[1])))
def get_interaction_rdm(qubit_operator, n_qubits=None): """Build an InteractionRDM from measured qubit operators. Returns: An InteractionRDM object. """ # Avoid circular import. from fermilib.transforms import jordan_wigner if n_qubits is None: n_qubits = count_qubits(qubit_operator) one_rdm = numpy.zeros((n_qubits, ) * 2, dtype=complex) two_rdm = numpy.zeros((n_qubits, ) * 4, dtype=complex) # One-RDM. for i, j in itertools.product(range(n_qubits), repeat=2): transformed_operator = jordan_wigner(FermionOperator(((i, 1), (j, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: one_rdm[i, j] += coefficient * qubit_operator.terms[term] # Two-RDM. for i, j, k, l in itertools.product(range(n_qubits), repeat=4): transformed_operator = jordan_wigner( FermionOperator(((i, 1), (j, 1), (k, 0), (l, 0)))) for term, coefficient in iteritems(transformed_operator.terms): if term in qubit_operator.terms: two_rdm[i, j, k, l] += coefficient * qubit_operator.terms[term] return InteractionRDM(one_rdm, two_rdm)
def plane_wave_kinetic(grid, spinless=False): """Return the kinetic energy operator in the plane wave basis. Args: grid (fermilib.utils.Grid): The discretization to use. spinless (bool): Whether to use the spinless model or not. Returns: FermionOperator: The kinetic momentum operator. """ # Initialize. operator = FermionOperator() spins = [None] if spinless else [0, 1] # Loop once through all plane waves. for momenta_indices in grid.all_points_indices(): momenta = momentum_vector(momenta_indices, grid) coefficient = momenta.dot(momenta) / 2. # Loop over spins. for spin in spins: orbital = orbital_id(grid, momenta_indices, spin) # Add interaction term. operators = ((orbital, 1), (orbital, 0)) operator += FermionOperator(operators, coefficient) return operator
def test_zero(self): n_qubits = 5 transmed_i = reverse_jordan_wigner(QubitOperator(), n_qubits) expected_i = FermionOperator() self.assertTrue(transmed_i.isclose(expected_i)) retransmed_i = jordan_wigner(transmed_i) self.assertTrue(expected_i.isclose(retransmed_i))
def test_ccr_offsite_even_cc(self): c2 = FermionOperator(((2, 1), )) c4 = FermionOperator(((4, 1), )) self.assertTrue( normal_ordered(c2 * c4).isclose(normal_ordered(-c4 * c2))) self.assertTrue( jordan_wigner(c2 * c4).isclose(jordan_wigner(-c4 * c2)))
def test_ccr_offsite_odd_cc(self): c1 = FermionOperator(((1, 1), )) c4 = FermionOperator(((4, 1), )) self.assertTrue( normal_ordered(c1 * c4).isclose(normal_ordered(-c4 * c1))) self.assertTrue( jordan_wigner(c1 * c4).isclose(jordan_wigner(-c4 * c1)))
def test_ccr_offsite_even_aa(self): a2 = FermionOperator(((2, 0), )) a4 = FermionOperator(((4, 0), )) self.assertTrue( normal_ordered(a2 * a4).isclose(normal_ordered(-a4 * a2))) self.assertTrue( jordan_wigner(a2 * a4).isclose(jordan_wigner(-a4 * a2)))
def test_ccr_offsite_odd_aa(self): a1 = FermionOperator(((1, 0), )) a4 = FermionOperator(((4, 0), )) self.assertTrue( normal_ordered(a1 * a4).isclose(normal_ordered(-a4 * a1))) self.assertTrue( jordan_wigner(a1 * a4).isclose(jordan_wigner(-a4 * a1)))
def test_get_interaction_operator_one_body_twoterm(self): interaction_operator = get_interaction_operator( FermionOperator('2^ 3', -2j) + FermionOperator('3^ 2', 3j), self.n_qubits) one_body = numpy.zeros((self.n_qubits, self.n_qubits), complex) one_body[2, 3] = -2j one_body[3, 2] = 3j self.assertEqual(interaction_operator, InteractionOperator(0.0, one_body, self.two_body))
def benchmark_fermion_math_and_normal_order(n_qubits, term_length, power): """Benchmark both arithmetic operators and normal ordering on fermions. The idea is we generate two random FermionTerms, A and B, each acting on n_qubits with term_length operators. We then compute (A + B) ** power. This is costly that is the first benchmark. The second benchmark is in normal ordering whatever comes out. Args: n_qubits: The number of qubits on which these terms act. term_length: The number of operators in each term. power: Int, the exponent to which to raise sum of the two terms. Returns: runtime_math: The time it takes to perform (A + B) ** power runtime_normal_order: The time it takes to perform FermionOperator.normal_order() """ # Generate random operator strings. operators_a = [(numpy.random.randint(n_qubits), numpy.random.randint(2))] operators_b = [(numpy.random.randint(n_qubits), numpy.random.randint(2))] for operator_number in range(term_length): # Make sure the operator is not trivially zero. operator_a = (numpy.random.randint(n_qubits), numpy.random.randint(2)) while operator_a == operators_a[-1]: operator_a = (numpy.random.randint(n_qubits), numpy.random.randint(2)) operators_a += [operator_a] # Do the same for the other operator. operator_b = (numpy.random.randint(n_qubits), numpy.random.randint(2)) while operator_b == operators_b[-1]: operator_b = (numpy.random.randint(n_qubits), numpy.random.randint(2)) operators_b += [operator_b] # Initialize FermionTerms and then sum them together. fermion_term_a = FermionOperator(tuple(operators_a), float(numpy.random.randn())) fermion_term_b = FermionOperator(tuple(operators_b), float(numpy.random.randn())) fermion_operator = fermion_term_a + fermion_term_b # Exponentiate. start_time = time.time() fermion_operator **= power runtime_math = time.time() - start_time # Normal order. start_time = time.time() normal_ordered(fermion_operator) runtime_normal_order = time.time() - start_time # Return. return runtime_math, runtime_normal_order
def plane_wave_u_operator(n_dimensions, grid_length, length_scale, nuclear_charges, spinless): """Return the external potential operator in plane wave basis. Args: n_dimensions: An int giving the number of dimensions for the model. grid_length: Int, the number of points in one dimension of the grid. length_scale: Float, the real space length of a box dimension. nuclear_charges: 3D int array, the nuclear charges. spinless: Bool, whether to use the spinless model or not. Returns: operator: An instance of the FermionOperator class. """ n_points = grid_length**n_dimensions volume = length_scale**float(n_dimensions) prefactor = -4.0 * numpy.pi / volume operator = None if spinless: spins = [None] else: spins = [0, 1] for grid_indices_p in itertools.product(range(grid_length), repeat=n_dimensions): for grid_indices_q in itertools.product(range(grid_length), repeat=n_dimensions): shift = grid_length // 2 grid_indices_p_q = [ (grid_indices_p[i] - grid_indices_q[i] + shift) % grid_length for i in range(n_dimensions) ] momenta_p_q = momentum_vector(grid_indices_p_q, grid_length, length_scale) momenta_p_q_squared = momenta_p_q.dot(momenta_p_q) if momenta_p_q_squared < EQ_TOLERANCE: continue for grid_indices_j in itertools.product(range(grid_length), repeat=n_dimensions): coordinate_j = position_vector(grid_indices_j, grid_length, length_scale) exp_index = 1.0j * momenta_p_q.dot(coordinate_j) coefficient = prefactor / momenta_p_q_squared * \ nuclear_charges[grid_indices_j] * numpy.exp(exp_index) for spin in spins: orbital_p = orbital_id(grid_length, grid_indices_p, spin) orbital_q = orbital_id(grid_length, grid_indices_q, spin) operators = ((orbital_p, 1), (orbital_q, 0)) if operator is None: operator = FermionOperator(operators, coefficient) else: operator += FermionOperator(operators, coefficient) return operator
def test_z(self): pauli_z = QubitOperator(((2, 'Z'), )) transmed_z = reverse_jordan_wigner(pauli_z) expected = (FermionOperator(()) + FermionOperator( ((2, 1), (2, 0)), -2.)) self.assertTrue(transmed_z.isclose(expected)) retransmed_z = jordan_wigner(transmed_z) self.assertTrue(pauli_z.isclose(retransmed_z))
def test_ccr_onsite(self): c1 = FermionOperator(((1, 1), )) a1 = hermitian_conjugated(c1) self.assertTrue( normal_ordered( c1 * a1).isclose(FermionOperator(()) - normal_ordered(a1 * c1))) self.assertTrue( jordan_wigner( c1 * a1).isclose(QubitOperator(()) - jordan_wigner(a1 * c1)))
def uccsd_operator(single_amplitudes, double_amplitudes, anti_hermitian=True): """Create a fermionic operator that is the generator of uccsd. This a the most straight-forward method to generate UCCSD operators, however it is slightly inefficient. In particular, it parameterizes all possible excitations, so it represents a generalized unitary coupled cluster ansatz, but also does not explicitly enforce the uniqueness in parametrization, so it is redundant. For example there will be a linear dependency in the ansatz of single_amplitudes[i,j] and single_amplitudes[j,i]. Args: single_amplitudes(list or ndarray): list of lists with each sublist storing a list of indices followed by single excitation amplitudes i.e. [[[i,j],t_ij], ...] OR [NxN] array storing single excitation amplitudes corresponding to t[i,j] * (a_i^\dagger a_j - H.C.) double_amplitudes(list or ndarray): list of lists with each sublist storing a list of indices followed by double excitation amplitudes i.e. [[[i,j,k,l],t_ijkl], ...] OR [NxNxNxN] array storing double excitation amplitudes corresponding to t[i,j,k,l] * (a_i^\dagger a_j a_k^\dagger a_l - H.C.) anti_hermitian(Bool): Flag to generate only normal CCSD operator rather than unitary variant, primarily for testing Returns: uccsd_generator(FermionOperator): Anti-hermitian fermion operator that is the generator for the uccsd wavefunction. """ uccsd_generator = FermionOperator() # Re-format inputs (ndarrays to lists) if necessary if (isinstance(single_amplitudes, numpy.ndarray) or isinstance(double_amplitudes, numpy.ndarray)): single_amplitudes, double_amplitudes = convert_amplitude_format( single_amplitudes, double_amplitudes) # Add single excitations for (i, j), t_ij in single_amplitudes: i, j = int(i), int(j) uccsd_generator += FermionOperator(((i, 1), (j, 0)), t_ij) if anti_hermitian: uccsd_generator += FermionOperator(((j, 1), (i, 0)), -t_ij) # Add double excitations for (i, j, k, l), t_ijkl in double_amplitudes: i, j, k, l = int(i), int(j), int(k), int(l) uccsd_generator += FermionOperator( ((i, 1), (j, 0), (k, 1), (l, 0)), t_ijkl) if anti_hermitian: uccsd_generator += FermionOperator( ((l, 1), (k, 0), (j, 1), (i, 0)), -t_ijkl) return uccsd_generator
def test_yy(self): yy = QubitOperator(((2, 'Y'), (3, 'Y')), 2.) transmed_yy = reverse_jordan_wigner(yy) retransmed_yy = jordan_wigner(transmed_yy) expected1 = -(FermionOperator(((2, 1), ), 2.) + FermionOperator( ((2, 0), ), 2.)) expected2 = (FermionOperator(((3, 1), )) - FermionOperator(((3, 0), ))) expected = expected1 * expected2 self.assertTrue(yy.isclose(retransmed_yy)) self.assertTrue( normal_ordered(transmed_yy).isclose(normal_ordered(expected)))
def test_xy(self): xy = QubitOperator(((4, 'X'), (5, 'Y')), -2.j) transmed_xy = reverse_jordan_wigner(xy) retransmed_xy = jordan_wigner(transmed_xy) expected1 = -2j * (FermionOperator(((4, 1), ), 1j) - FermionOperator( ((4, 0), ), 1j)) expected2 = (FermionOperator(((5, 1), )) - FermionOperator(((5, 0), ))) expected = expected1 * expected2 self.assertTrue(xy.isclose(retransmed_xy)) self.assertTrue( normal_ordered(transmed_xy).isclose(normal_ordered(expected)))
def test_sparse_uccsd_operator_numpy_inputs(self): """Test numpy ndarray inputs to uccsd_operator that are sparse""" test_orbitals = 30 sparse_single_amplitudes = numpy.zeros((test_orbitals, test_orbitals)) sparse_double_amplitudes = numpy.zeros( (test_orbitals, test_orbitals, test_orbitals, test_orbitals)) sparse_single_amplitudes[3, 5] = 0.12345 sparse_single_amplitudes[12, 4] = 0.44313 sparse_double_amplitudes[0, 12, 6, 2] = 0.3434 sparse_double_amplitudes[1, 4, 6, 13] = -0.23423 generator = uccsd_operator(sparse_single_amplitudes, sparse_double_amplitudes) test_generator = (0.12345 * FermionOperator("3^ 5") + (-0.12345) * FermionOperator("5^ 3") + 0.44313 * FermionOperator("12^ 4") + (-0.44313) * FermionOperator("4^ 12") + 0.3434 * FermionOperator("0^ 12 6^ 2") + (-0.3434) * FermionOperator("2^ 6 12^ 0") + (-0.23423) * FermionOperator("1^ 4 6^ 13") + 0.23423 * FermionOperator("13^ 6 4^ 1")) self.assertTrue(test_generator.isclose(generator))
def test_bk_jw_hopping_operator(self): # Check if the spectrum fits for a single hoppping operator n_qubits = 5 ho = FermionOperator(((1, 1), (4, 0))) + FermionOperator( ((4, 1), (1, 0))) jw_ho = jordan_wigner(ho) bk_ho = bravyi_kitaev(ho) # Diagonalize and make sure the spectra are the same. jw_spectrum = eigenspectrum(jw_ho) bk_spectrum = eigenspectrum(bk_ho) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(jw_spectrum - bk_spectrum)))
def test_yx(self): yx = QubitOperator(((0, 'Y'), (1, 'X')), -0.5) transmed_yx = reverse_jordan_wigner(yx) retransmed_yx = jordan_wigner(transmed_yx) expected1 = 1j * (FermionOperator(((0, 1), )) + FermionOperator( ((0, 0), ))) expected2 = -0.5 * (FermionOperator(((1, 1), )) + FermionOperator( ((1, 0), ))) expected = expected1 * expected2 self.assertTrue(yx.isclose(retransmed_yx)) self.assertTrue( normal_ordered(transmed_yx).isclose(normal_ordered(expected)))
def test_jw_restrict_operator_hopping_to_1_particle_default_nqubits(self): interaction = (FermionOperator('3^ 2^ 4 1') + FermionOperator('4^ 1^ 3 2')) interaction_sparse = jordan_wigner_sparse(interaction, n_qubits=6) # n_qubits should default to 6 interaction_restrict = jw_number_restrict_operator( interaction_sparse, 2) dim = 6 * 5 / 2 # shape of new sparse array # 3^ 2^ 4 1 maps 2**4 + 2 = 18 to 2**3 + 2**2 = 12 and vice versa; # in the 2-particle subspace (1, 4) and (2, 3) are 7th and 9th. expected = csc_matrix(([-1, -1], ([7, 9], [9, 7])), shape=(dim, dim)) self.assertTrue(numpy.allclose(interaction_restrict.A, expected.A))
def uccsd_operator(single_amplitudes, double_amplitudes, anti_hermitian=True): """Create a fermionic operator that is the generator of uccsd. This a the most straight-forward method to generate UCCSD operators, however it is slightly inefficient. In particular, it parameterizes all possible exictations, so it represents a generalized unitary coupled cluster ansatz, but also does not explicitly enforce the uniqueness in paramterization, so it is redundant. For example there will be a linear dependency in the ansatz of single_amplitudes[i,j] and single_amplitudes[j,i]. Args: single_amplitudes(ndarray): [NxN] array storing single excitation amplitudes corresponding to t[i,j] * (a_i^\dagger a_j + H.C.) double_amplitudes(ndarray): [NxNxNxN] array storing double excitation amplitudes corresponding to t[i,j,k,l] * (a_i^\dagger a_j a_k^\dagger a_l + H.C.) anti_hermitian(Bool): Flag to generate only normal CCSD operator rather than unitary variant, primarily for testing Returns: uccsd_generator(FermionOperator): Anti-hermitian fermion operator that is the generator for the uccsd wavefunction. """ n_orbitals = single_amplitudes.shape[0] assert (n_orbitals == double_amplitudes.shape[0]) uccsd_generator = FermionOperator() # Add single excitations for i, j in itertools.product(range(n_orbitals), repeat=2): if single_amplitudes[i, j] == 0.: continue uccsd_generator += FermionOperator(((i, 1), (j, 0)), single_amplitudes[i, j]) if (anti_hermitian): uccsd_generator += FermionOperator(((j, 1), (i, 0)), -single_amplitudes[i, j]) # Add double excitations for i, j, k, l in itertools.product(range(n_orbitals), repeat=4): if double_amplitudes[i, j, k, l] == 0.: continue uccsd_generator += FermionOperator(((i, 1), (j, 0), (k, 1), (l, 0)), double_amplitudes[i, j, k, l]) if (anti_hermitian): uccsd_generator += FermionOperator( ((l, 1), (k, 0), (j, 1), (i, 0)), -double_amplitudes[i, j, k, l]) return uccsd_generator
def test_xx(self): xx = QubitOperator(((3, 'X'), (4, 'X')), 2.) transmed_xx = reverse_jordan_wigner(xx) retransmed_xx = jordan_wigner(transmed_xx) expected1 = (FermionOperator(((3, 1), ), 2.) - FermionOperator( ((3, 0), ), 2.)) expected2 = (FermionOperator(((4, 1), ), 1.) + FermionOperator( ((4, 0), ), 1.)) expected = expected1 * expected2 self.assertTrue(xx.isclose(retransmed_xx)) self.assertTrue( normal_ordered(transmed_xx).isclose(normal_ordered(expected)))
def test_jordan_wigner_one_body(self): # Make sure it agrees with jordan_wigner(FermionTerm). for p in range(self.n_qubits): for q in range(self.n_qubits): # Get test qubit operator. test_operator = jordan_wigner_one_body(p, q) # Get correct qubit operator. fermion_term = FermionOperator(((p, 1), (q, 0))) correct_op = jordan_wigner(fermion_term) hermitian_conjugate = hermitian_conjugated(fermion_term) if not fermion_term.isclose(hermitian_conjugate): correct_op += jordan_wigner(hermitian_conjugate) self.assertTrue(test_operator.isclose(correct_op))
def plane_wave_external_potential(grid, geometry, spinless): """Return the external potential operator in plane wave basis. 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. Returns: FermionOperator: The plane wave operator. """ prefactor = -4.0 * numpy.pi / grid.volume_scale() operator = None if spinless: spins = [None] else: spins = [0, 1] for indices_p in grid.all_points_indices(): for indices_q in grid.all_points_indices(): shift = grid.length // 2 grid_indices_p_q = [ (indices_p[i] - indices_q[i] + shift) % grid.length for i in range(grid.dimensions)] momenta_p_q = momentum_vector(grid_indices_p_q, grid) momenta_p_q_squared = momenta_p_q.dot(momenta_p_q) if momenta_p_q_squared < EQ_TOLERANCE: continue for nuclear_term in geometry: coordinate_j = numpy.array(nuclear_term[1]) exp_index = 1.0j * momenta_p_q.dot(coordinate_j) coefficient = (prefactor / momenta_p_q_squared * periodic_hash_table[nuclear_term[0]] * numpy.exp(exp_index)) for spin in spins: orbital_p = orbital_id(grid, indices_p, spin) orbital_q = orbital_id(grid, indices_q, spin) operators = ((orbital_p, 1), (orbital_q, 0)) if operator is None: operator = FermionOperator(operators, coefficient) else: operator += FermionOperator(operators, coefficient) return operator
def test_get_interaction_operator_one_body(self): interaction_operator = get_interaction_operator( FermionOperator('2^ 2'), self.n_qubits) one_body = numpy.zeros((self.n_qubits, self.n_qubits), float) one_body[2, 2] = 1. self.assertEqual(interaction_operator, InteractionOperator(0.0, one_body, self.two_body))
def test_qubit_jw_fermion_integration(self): # Initialize a random fermionic operator. fermion_operator = FermionOperator(((3, 1), (2, 1), (1, 0), (0, 0)), -4.3) fermion_operator += FermionOperator(((3, 1), (1, 0)), 8.17) fermion_operator += 3.2 * FermionOperator() # Map to qubits and compare matrix versions. qubit_operator = jordan_wigner(fermion_operator) qubit_sparse = get_sparse_operator(qubit_operator) qubit_spectrum = sparse_eigenspectrum(qubit_sparse) fermion_sparse = jordan_wigner_sparse(fermion_operator) fermion_spectrum = sparse_eigenspectrum(fermion_sparse) self.assertAlmostEqual( 0., numpy.amax(numpy.absolute(fermion_spectrum - qubit_spectrum)))