def test_error_operator(self): FO = FermionOperator terms = [] for i in range(4): terms.append(FO(((i, 1), ((i + 1) % 4, 0)), -0.0123370055014)) terms.append(FO(((i, 1), ((i - 1) % 4, 0)), -0.0123370055014)) if i in [0, 2]: terms.append( normal_ordered( FO(((i + 1, 1), (i, 1), (i + 1, 0), (i, 0)), 3.18309886184))) if i < 2: terms.append( normal_ordered( FO(((i, 1), ((i + 2) % 4, 1), (i, 0), ((i + 2) % 4, 0)), 22.2816920329))) self.assertAlmostEqual( low_depth_second_order_trotter_error_operator(terms).terms[((3, 1), (2, 1), (1, 1), (2, 0), (1, 0), (0, 0))], 0.75)
def test_quad_single_term(self): op = QuadOperator('p4 p3 p2 p1') + QuadOperator('p3 p2') self.assertTrue(op == normal_ordered(op)) op = QuadOperator('q0 p0') - QuadOperator('p0 q0') expected = QuadOperator('', 2.j) self.assertTrue(expected == normal_ordered(op, hbar=2.))
def test_convert_forward_back(self): n_qubits = 6 random_operator = get_fermion_operator( random_interaction_operator(n_qubits)) chemist_operator = chemist_ordered(random_operator) normalized_chemist = normal_ordered(chemist_operator) difference = normalized_chemist - normal_ordered(random_operator) self.assertAlmostEqual(0., difference.induced_norm())
def test_quad_triple(self): op_132 = QuadOperator(((1, 'p'), (3, 'q'), (2, 'q'))) op_123 = QuadOperator(((1, 'p'), (2, 'q'), (3, 'q'))) op_321 = QuadOperator(((3, 'q'), (2, 'q'), (1, 'p'))) self.assertTrue(op_132 == normal_ordered(op_123)) self.assertTrue(op_132 == normal_ordered(op_132)) self.assertTrue(op_132 == normal_ordered(op_321))
def test_fermion_triple(self): op_132 = FermionOperator(((1, 1), (3, 0), (2, 0))) op_123 = FermionOperator(((1, 1), (2, 0), (3, 0))) op_321 = FermionOperator(((3, 0), (2, 0), (1, 1))) self.assertTrue(op_132 == normal_ordered(-op_123)) self.assertTrue(op_132 == normal_ordered(op_132)) self.assertTrue(op_132 == normal_ordered(op_321))
def test_inverse_fourier_transform_2d(self): grid = Grid(dimensions=2, scale=1.5, length=3) spinless = True geometry = [('H', (0, 0)), ('H', (0.5, 0.8))] h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless, True) h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless, False) h_dual_basis_t = inverse_fourier_transform(h_dual_basis, grid, spinless) self.assertEqual(normal_ordered(h_dual_basis_t), normal_ordered(h_plane_wave))
def test_inverse_fourier_transform_1d(self): grid = Grid(dimensions=1, scale=1.5, length=4) spinless_set = [True, False] geometry = [('H', (0,)), ('H', (0.5,))] for spinless in spinless_set: h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless, True) h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless, False) h_dual_basis_t = inverse_fourier_transform(h_dual_basis, grid, spinless) self.assertEqual(normal_ordered(h_dual_basis_t), normal_ordered(h_plane_wave))
def test_erpa_eom_ham_lih(): filename = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5") molecule = MolecularData(filename=filename) reduced_ham = make_reduced_hamiltonian( molecule.get_molecular_hamiltonian(), molecule.n_electrons) rha_fermion = get_fermion_operator(reduced_ham) permuted_hijkl = np.einsum('ijlk', reduced_ham.two_body_tensor) opdm = np.diag([1] * molecule.n_electrons + [0] * (molecule.n_qubits - molecule.n_electrons)) tpdm = 2 * wedge(opdm, opdm, (1, 1), (1, 1)) rdms = InteractionRDM(opdm, tpdm) dim = 3 # so we don't do the full basis. This would make the test long full_basis = {} # erpa basis. A, B basis in RPA language cnt = 0 # start from 1 to make test shorter for p, q in product(range(1, dim), repeat=2): if p < q: full_basis[(p, q)] = cnt full_basis[(q, p)] = cnt + dim * (dim - 1) // 2 cnt += 1 for rkey in full_basis.keys(): p, q = rkey for ckey in full_basis.keys(): r, s = ckey for sigma, tau in product([0, 1], repeat=2): test = erpa_eom_hamiltonian(permuted_hijkl, tpdm, 2 * q + sigma, 2 * p + sigma, 2 * r + tau, 2 * s + tau).real qp_op = FermionOperator( ((2 * q + sigma, 1), (2 * p + sigma, 0))) rs_op = FermionOperator(((2 * r + tau, 1), (2 * s + tau, 0))) erpa_op = normal_ordered( commutator(qp_op, commutator(rha_fermion, rs_op))) true = rdms.expectation(get_interaction_operator(erpa_op)) assert np.isclose(true, test)
def test_interaction_operator(self): for n_orbitals, real, _ in itertools.product((1, 2, 5), (True, False), range(5)): operator = random_interaction_operator(n_orbitals, real=real) normal_ordered_operator = normal_ordered(operator) expected_qubit_operator = jordan_wigner(operator) actual_qubit_operator = jordan_wigner(normal_ordered_operator) assert expected_qubit_operator == actual_qubit_operator two_body_tensor = normal_ordered_operator.two_body_tensor n_orbitals = len(two_body_tensor) ones = numpy.ones((n_orbitals,) * 2) triu = numpy.triu(ones, 1) shape = (n_orbitals**2, 1) mask = (triu.reshape(shape) * ones.reshape(shape[::-1]) + ones.reshape(shape) * triu.reshape(shape[::-1])).reshape( (n_orbitals,) * 4) assert numpy.allclose(mask * two_body_tensor, numpy.zeros((n_orbitals,) * 4)) for term in normal_ordered_operator: order = len(term) // 2 left_term, right_term = term[:order], term[order:] assert all(i[1] == 1 for i in left_term) assert all(i[1] == 0 for i in right_term) assert left_term == tuple(sorted(left_term, reverse=True)) assert right_term == tuple(sorted(right_term, reverse=True))
def setUp(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = 'sto-3g' multiplicity = 1 filename = os.path.join(THIS_DIRECTORY, 'data', 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(geometry, basis, multiplicity, filename=filename) self.molecule.load() # Get molecular Hamiltonian. self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian() # Get FCI RDM. self.fci_rdm = self.molecule.get_molecular_rdm(use_fci=1) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get fermion Hamiltonian. self.fermion_hamiltonian = normal_ordered( get_fermion_operator(self.molecular_hamiltonian)) # Get qubit Hamiltonian. self.qubit_hamiltonian = jordan_wigner(self.fermion_hamiltonian) # Get the sparse matrix. self.hamiltonian_matrix = get_sparse_operator( self.molecular_hamiltonian)
def double_commutator(op1, op2, op3, indices2=None, indices3=None, is_hopping_operator2=None, is_hopping_operator3=None): """Return the double commutator [op1, [op2, op3]]. Args: op1, op2, op3 (FermionOperators or BosonOperators): operators for the commutator. All three operators must be of the same type. indices2, indices3 (set): The indices op2 and op3 act on. is_hopping_operator2 (bool): Whether op2 is a hopping operator. is_hopping_operator3 (bool): Whether op3 is a hopping operator. Returns: The double commutator of the given operators. """ if is_hopping_operator2 and is_hopping_operator3: indices2 = set(indices2) indices3 = set(indices3) # Determine which indices both op2 and op3 act on. try: intersection, = indices2.intersection(indices3) except ValueError: return FermionOperator.zero() # Remove the intersection from the set of indices, since it will get # cancelled out in the final result. indices2.remove(intersection) indices3.remove(intersection) # Find the indices of the final output hopping operator. index2, = indices2 index3, = indices3 coeff2 = op2.terms[list(op2.terms)[0]] coeff3 = op3.terms[list(op3.terms)[0]] commutator23 = (FermionOperator( ((index2, 1), (index3, 0)), coeff2 * coeff3) + FermionOperator( ((index3, 1), (index2, 0)), -coeff2 * coeff3)) else: commutator23 = normal_ordered(commutator(op2, op3)) return normal_ordered(commutator(op1, commutator23))
def test_molecular_operator_consistency(self): # Initialize H2 InteractionOperator. n_qubits = 4 filename = os.path.join(THIS_DIRECTORY, 'data', 'H2_sto-3g_singlet_0.7414') molecule = MolecularData(filename=filename) molecule_interaction = molecule.get_molecular_hamiltonian() molecule_operator = get_fermion_operator(molecule_interaction) constant = molecule_interaction.constant one_body_coefficients = molecule_interaction.one_body_tensor two_body_coefficients = molecule_interaction.two_body_tensor # Perform decomposition. eigenvalues, one_body_squares, one_body_corrections, trunc_error = ( low_rank_two_body_decomposition(two_body_coefficients)) self.assertAlmostEqual(trunc_error, 0.) # Build back operator constant and one-body components. decomposed_operator = FermionOperator((), constant) for p, q in itertools.product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = (one_body_coefficients[p, q] + one_body_corrections[p, q]) decomposed_operator += FermionOperator(term, coefficient) # Build back two-body component. for l in range(one_body_squares.shape[0]): one_body_operator = FermionOperator() for p, q in itertools.product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_squares[l, p, q] if abs(eigenvalues[l]) > 1e-6: self.assertTrue(is_hermitian(one_body_squares[l])) one_body_operator += FermionOperator(term, coefficient) decomposed_operator += eigenvalues[l] * (one_body_operator**2) # Test for consistency. difference = normal_ordered(decomposed_operator - molecule_operator) self.assertAlmostEqual(0., difference.induced_norm()) # Decompose with slightly negative operator that must use eigen molecule = MolecularData(filename=filename) molecule.two_body_integrals[0, 0, 0, 0] -= 1 eigenvalues, one_body_squares, one_body_corrections, trunc_error = ( low_rank_two_body_decomposition(two_body_coefficients)) self.assertAlmostEqual(trunc_error, 0.) # Check for property errors with self.assertRaises(TypeError): eigenvalues, one_body_squares, _, trunc_error = ( low_rank_two_body_decomposition(two_body_coefficients + 0.01j, truncation_threshold=1., final_rank=1))
def test_sum_of_ordered_terms_equals_full_hamiltonian_odd_side_len(self): hamiltonian = normal_ordered( fermi_hubbard(5, 5, 1.0, -0.3, periodic=False)) hamiltonian.compress() terms = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian)[0] terms_total = sum(terms, FermionOperator.zero()) self.assertTrue(terms_total == hamiltonian)
def test_total_length_odd_side_length_full_hubbard(self): hamiltonian = normal_ordered( fermi_hubbard(5, 5, -1., -0.3, periodic=False)) hamiltonian.compress() # Unpack result into terms, indices they act on, and whether they're # hopping operators. result = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian) terms, _, _ = result self.assertEqual(len(terms), 105)
def get_qubit_expectations(self, qubit_operator): """Return expectations of QubitOperator in new QubitOperator. Args: qubit_operator: QubitOperator instance to be evaluated on this InteractionRDM. Returns: QubitOperator: QubitOperator with coefficients corresponding to expectation values of those operators. Raises: InteractionRDMError: Observable not contained in 1-RDM or 2-RDM. """ from openfermion.transforms.opconversions import reverse_jordan_wigner from openfermion.utils.operator_utils import normal_ordered qubit_operator_expectations = copy.deepcopy(qubit_operator) for qubit_term in qubit_operator_expectations.terms: expectation = 0. # Map qubits back to fermions. reversed_fermion_operators = reverse_jordan_wigner( QubitOperator(qubit_term)) reversed_fermion_operators = normal_ordered( reversed_fermion_operators) # Loop through fermion terms. for fermion_term in reversed_fermion_operators.terms: coefficient = reversed_fermion_operators.terms[fermion_term] # Handle molecular term. if FermionOperator( fermion_term).is_two_body_number_conserving(): if not fermion_term: expectation += coefficient else: indices = [operator[0] for operator in fermion_term] if len(indices) == 2: # One-body term indices = tuple(zip(indices, (1, 0))) else: # Two-body term indices = tuple(zip(indices, (1, 1, 0, 0))) rdm_element = self[indices] expectation += rdm_element * coefficient # Handle non-molecular terms. elif len(fermion_term) > 4: raise InteractionRDMError('Observable not contained ' 'in 1-RDM or 2-RDM.') qubit_operator_expectations.terms[qubit_term] = expectation return qubit_operator_expectations
def test_split_operator_error_operator_VT_order_against_definition(self): hamiltonian = (normal_ordered(fermi_hubbard(3, 3, 1., 4.0)) - 2.3 * FermionOperator.identity()) 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()) error_operator = ( split_operator_trotter_error_operator_diagonal_two_body( hamiltonian, order='V+T')) # V-then-T ordered double commutators: [V, [T, V]] + [T, [T, V]] / 2 inner_commutator = normal_ordered(commutator(kinetic, potential)) error_operator_definition = normal_ordered( commutator(potential, inner_commutator)) error_operator_definition += normal_ordered( commutator(kinetic, inner_commutator)) / 2.0 error_operator_definition /= 12.0 self.assertEqual(error_operator, error_operator_definition)
def test_fourier_transform(self): for length in [2, 3]: grid = Grid(dimensions=1, scale=1.5, length=length) spinless_set = [True, False] geometry = [('H', (0.1,)), ('H', (0.5,))] for spinless in spinless_set: h_plane_wave = plane_wave_hamiltonian(grid, geometry, spinless, True) h_dual_basis = plane_wave_hamiltonian(grid, geometry, spinless, False) h_plane_wave_t = fourier_transform(h_plane_wave, grid, spinless) self.assertEqual(normal_ordered(h_plane_wave_t), normal_ordered(h_dual_basis)) # Verify that all 3 are Hermitian plane_wave_operator = get_sparse_operator(h_plane_wave) dual_operator = get_sparse_operator(h_dual_basis) plane_wave_t_operator = get_sparse_operator(h_plane_wave_t) self.assertTrue(is_hermitian(plane_wave_operator)) self.assertTrue(is_hermitian(dual_operator)) self.assertTrue(is_hermitian(plane_wave_t_operator))
def test_sum_of_ordered_terms_equals_full_side_length_2_hopping_only(self): hamiltonian = normal_ordered( fermi_hubbard(2, 2, 1., 0.0, periodic=False)) hamiltonian.compress() # Unpack result into terms, indices they act on, and whether they're # hopping operators. result = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian) terms, _, _ = result terms_total = sum(terms, FermionOperator.zero()) self.assertTrue(terms_total == hamiltonian)
def test_operator_consistency_w_spin(self): # Initialize a random InteractionOperator and FermionOperator. n_orbitals = 3 n_qubits = 2 * n_orbitals random_interaction = random_interaction_operator(n_orbitals, expand_spin=True, real=False, seed=8) random_fermion = get_fermion_operator(random_interaction) # Convert to chemist ordered tensor. one_body_correction, chemist_tensor = \ get_chemist_two_body_coefficients( random_interaction.two_body_tensor, spin_basis=True) # Convert output to FermionOperator. output_operator = FermionOperator((), random_interaction.constant) # Convert one-body. one_body_coefficients = (random_interaction.one_body_tensor + one_body_correction) for p, q in itertools.product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_coefficients[p, q] output_operator += FermionOperator(term, coefficient) # Convert two-body. for p, q, r, s in itertools.product(range(n_orbitals), repeat=4): coefficient = chemist_tensor[p, q, r, s] # Mixed spin. term = ((2 * p, 1), (2 * q, 0), (2 * r + 1, 1), (2 * s + 1, 0)) output_operator += FermionOperator(term, coefficient) term = ((2 * p + 1, 1), (2 * q + 1, 0), (2 * r, 1), (2 * s, 0)) output_operator += FermionOperator(term, coefficient) # Same spin. term = ((2 * p, 1), (2 * q, 0), (2 * r, 1), (2 * s, 0)) output_operator += FermionOperator(term, coefficient) term = ((2 * p + 1, 1), (2 * q + 1, 0), (2 * r + 1, 1), (2 * s + 1, 0)) output_operator += FermionOperator(term, coefficient) # Check that difference is small. difference = normal_ordered(random_fermion - output_operator) self.assertAlmostEqual(0., difference.induced_norm())
def test_error_bound_using_info_even_side_length(self): # Generate the Hamiltonian. hamiltonian = normal_ordered( fermi_hubbard(4, 4, 0.5, 0.2, periodic=False)) hamiltonian.compress() # Unpack result into terms, indices they act on, and whether they're # hopping operators. result = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian) terms, indices, is_hopping = result self.assertAlmostEqual( low_depth_second_order_trotter_error_bound(terms, indices, is_hopping), 13.59)
def test_is_hopping_operator_terms_with_info(self): hamiltonian = normal_ordered( fermi_hubbard(5, 5, 1., -1., periodic=False)) hamiltonian.compress() # Unpack result into terms, indices they act on, and whether they're # hopping operators. result = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian) terms, _, 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_strong_interaction_hubbard_VT_order_gives_larger_error(self): hamiltonian = normal_ordered(fermi_hubbard(4, 4, 1., 10.0)) 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 test_intermediate_interaction_hubbard_TV_order_has_larger_error(self): hamiltonian = normal_ordered(fermi_hubbard(4, 4, 1., 4.0)) 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.assertAlmostEqual(TV_error_bound, 1706.66666666666) self.assertAlmostEqual(VT_error_bound, 1365.33333333333)
def setUp(self): # Set up molecule. geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] basis = 'sto-3g' multiplicity = 1 filename = os.path.join(THIS_DIRECTORY, 'data', 'H1-Li1_sto-3g_singlet_1.45') self.molecule = MolecularData(geometry, basis, multiplicity, filename=filename) self.molecule.load() # Get molecular Hamiltonian self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian() self.molecular_hamiltonian_no_core = ( self.molecule.get_molecular_hamiltonian( occupied_indices=[0], active_indices=range(1, self.molecule.n_orbitals))) # Get FCI RDM. self.fci_rdm = self.molecule.get_molecular_rdm(use_fci=1) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get fermion Hamiltonian. self.fermion_hamiltonian = normal_ordered( get_fermion_operator(self.molecular_hamiltonian)) # Get qubit Hamiltonian. self.qubit_hamiltonian = jordan_wigner(self.fermion_hamiltonian) # Get explicit coefficients. self.nuclear_repulsion = self.molecular_hamiltonian.constant self.one_body = self.molecular_hamiltonian.one_body_tensor self.two_body = self.molecular_hamiltonian.two_body_tensor # Get matrix form. self.hamiltonian_matrix = get_sparse_operator( self.molecular_hamiltonian) self.hamiltonian_matrix_no_core = get_sparse_operator( self.molecular_hamiltonian_no_core)
def test_correct_indices_terms_with_info(self): hamiltonian = normal_ordered( fermi_hubbard(5, 5, 1., -1., periodic=False)) hamiltonian.compress() # Unpack result into terms, indices they act on, and whether they're # hopping operators. result = simulation_ordered_grouped_hubbard_terms_with_info( hamiltonian) terms, indices, _ = 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_hubbard_trotter_error_matches_low_depth_trotter_error(self): hamiltonian = normal_ordered(fermi_hubbard(3, 3, 1., 2.3)) 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_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 diagonal_coulomb_potential_and_kinetic_terms_as_arrays(hamiltonian): """Give the potential and kinetic terms of a diagonal Coulomb Hamiltonian as arrays. Args: hamiltonian (FermionOperator): The diagonal Coulomb Hamiltonian to separate the potential and kinetic terms for. Identity is arbitrarily chosen to be part of the potential. Returns: Tuple of (potential_terms, kinetic_terms). Both elements of the tuple are numpy arrays of FermionOperators. """ if not isinstance(hamiltonian, FermionOperator): try: hamiltonian = normal_ordered(get_fermion_operator(hamiltonian)) except TypeError: raise TypeError('hamiltonian must be either a FermionOperator ' 'or DiagonalCoulombHamiltonian.') potential = FermionOperator.zero() kinetic = FermionOperator.zero() for term, coeff in hamiltonian.terms.items(): acted = set(term[i][0] for i in range(len(term))) if len(acted) == len(term) / 2: potential += FermionOperator(term, coeff) else: kinetic += FermionOperator(term, coeff) potential_terms = numpy.array([ FermionOperator(term, coeff) for term, coeff in potential.terms.items() ]) kinetic_terms = numpy.array( [FermionOperator(term, coeff) for term, coeff in kinetic.terms.items()]) return (potential_terms, kinetic_terms)
def test_random_operator_consistency(self): # Initialize a random InteractionOperator and FermionOperator. n_orbitals = 3 n_qubits = 2 * n_orbitals random_interaction = random_interaction_operator(n_orbitals, expand_spin=True, real=True, seed=8) random_fermion = get_fermion_operator(random_interaction) # Decompose. eigenvalues, one_body_squares, one_body_correction, error = ( low_rank_two_body_decomposition( random_interaction.two_body_tensor)) self.assertFalse(error) # Build back operator constant and one-body components. decomposed_operator = FermionOperator((), random_interaction.constant) one_body_coefficients = (random_interaction.one_body_tensor + one_body_correction) for p, q in itertools.product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_coefficients[p, q] decomposed_operator += FermionOperator(term, coefficient) # Build back two-body component. for l in range(n_orbitals**2): one_body_operator = FermionOperator() for p, q in itertools.product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_squares[l, p, q] one_body_operator += FermionOperator(term, coefficient) decomposed_operator += eigenvalues[l] * (one_body_operator**2) # Test for consistency. difference = normal_ordered(decomposed_operator - random_fermion) self.assertAlmostEqual(0., difference.induced_norm())
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())