def test_consistency(self): """Test consistency with JW for FermionOperators.""" # Random interaction operator n_qubits = 5 iop = random_interaction_operator(n_qubits, real=False) op1 = jordan_wigner(iop) op2 = jordan_wigner(get_fermion_operator(iop)) self.assertEqual(op1, op2) # Interaction operator from molecule geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] basis = 'sto-3g' multiplicity = 1 filename = os.path.join(DATA_DIRECTORY, 'H1-Li1_sto-3g_singlet_1.45') molecule = MolecularData(geometry, basis, multiplicity, filename=filename) molecule.load() iop = molecule.get_molecular_hamiltonian() op1 = jordan_wigner(iop) op2 = jordan_wigner(get_fermion_operator(iop)) self.assertEqual(op1, op2)
def lih_hamiltonian(): """ Generate test Hamiltonian from LiH. Args: None Return: hamiltonian: FermionicOperator spectrum: List of energies. """ geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] active_space_start = 1 active_space_stop = 3 molecule = MolecularData(geometry, 'sto-3g', 1, description="1.45") molecule.load() molecular_hamiltonian = molecule.get_molecular_hamiltonian( occupied_indices=range(active_space_start), active_indices=range(active_space_start, active_space_stop)) hamiltonian = get_fermion_operator(molecular_hamiltonian) spectrum = eigenspectrum(hamiltonian) return hamiltonian, spectrum
def make_molecule(self, *args, **kwargs) -> MolecularData: """Creates a molecule in openfermion format by running psi4 and extracting the data Will check for previous outputfiles before running Will not recompute if a file was found Parameters ---------- parameters : An instance of ParametersQC, which also holds an instance of ParametersPsi4 via parameters.psi4 The molecule will be saved in parameters.filename, if this file exists before the call the molecule will be imported from the file Returns ------- type the molecule in openfermion.MolecularData format """ molecule = MolecularData(**self.parameters.molecular_data_param) # try to load do_compute = True try: import os if os.path.exists(self.parameters.filename): molecule.load() do_compute = False except OSError: do_compute = True if do_compute: molecule = self.do_make_molecule(*args, **kwargs) molecule.save() return molecule
def plot_data(bond_lengths, data): basis = 'sto-3g' multiplicity = 1 bond_length_interval = 0.1 n_points = 25 # Generate molecule at different bond lengths. hf_energies = [] fci_energies = [] for bond_length in bond_lengths: description = str(round(bond_length, 2)) # print(description) geometry = [('H', (0., 0., 0.)), ('H', (0., 0., bond_length))] molecule = MolecularData(geometry, basis, multiplicity, description=description) # Load data. molecule.load() hf_energies += [molecule.hf_energy] fci_energies += [molecule.fci_energy] plt.figure(0) plt.plot(bond_lengths, fci_energies, 'x-') plt.plot(bond_lengths, [e for e, _ in data], 'o-') plt.ylabel('Energy in Hartree') plt.xlabel('Bond length in angstrom') plt.show()
def get_single_two_body_file(molecule_file_name): """ Loads the molecule from a file. :param molecule_file_name: Filename :return: Molecule """ molecule = MolecularData(filename=molecule_file_name) molecule.load() # _molecule = run_pyscf(molecule) return molecule.one_body_integrals, molecule.two_body_integrals
class InteractionRDMTest(unittest.TestCase): 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() self.cisd_energy = self.molecule.cisd_energy self.rdm = self.molecule.get_molecular_rdm() self.hamiltonian = self.molecule.get_molecular_hamiltonian() def test_get_qubit_expectations(self): qubit_operator = jordan_wigner(self.hamiltonian) qubit_expectations = self.rdm.get_qubit_expectations(qubit_operator) test_energy = 0.0 for qubit_term in qubit_expectations.terms: term_coefficient = qubit_operator.terms[qubit_term] test_energy += (term_coefficient * qubit_expectations.terms[qubit_term]) self.assertLess(abs(test_energy - self.cisd_energy), EQ_TOLERANCE) def test_get_qubit_expectations_nonmolecular_term(self): with self.assertRaises(InteractionRDMError): self.rdm.get_qubit_expectations(QubitOperator('X1 X2 X3 X4 Y6')) def test_get_qubit_expectations_through_expectation_method(self): qubit_operator = jordan_wigner(self.hamiltonian) test_energy = self.rdm.expectation(qubit_operator) self.assertLess(abs(test_energy - self.cisd_energy), EQ_TOLERANCE) def test_get_molecular_operator_expectation(self): expectation = self.rdm.expectation(self.hamiltonian) self.assertAlmostEqual(expectation, self.cisd_energy, places=7) def test_expectation_bad_type(self): with self.assertRaises(InteractionRDMError): self.rdm.expectation(12) def test_addition(self): rdm2 = self.rdm + self.rdm self.assertTrue( numpy.array_equal(rdm2.one_body_tensor, rdm2.n_body_tensors[(1, 0)])) self.assertTrue( numpy.array_equal(rdm2.two_body_tensor, rdm2.n_body_tensors[(1, 1, 0, 0)]))
def lih_hamiltonian(): geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] active_space_start = 1 active_space_stop = 3 molecule = MolecularData(geometry, 'sto-3g', 1, description="1.45") molecule.load() molecular_hamiltonian = molecule.get_molecular_hamiltonian( occupied_indices=range(active_space_start), active_indices=range(active_space_start, active_space_stop)) hamiltonian = get_fermion_operator(molecular_hamiltonian) ground_state_energy = eigenspectrum(hamiltonian)[0] return hamiltonian, ground_state_energy
def LiH_sto3g(): """ Generates the Hamiltonian for LiH in the STO-3G basis, at a distance of 1.45 A. """ geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))] molecule = MolecularData(geometry, 'sto-3g', 1, description="1.45") molecule.load() molecular_hamiltonian = molecule.get_molecular_hamiltonian() hamiltonian = get_fermion_operator(molecular_hamiltonian) num_electrons = molecule.n_electrons num_orbitals = 2 * molecule.n_orbitals return hamiltonian, num_orbitals, num_electrons
def setUp(self): # Setup. 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') molecule = MolecularData( geometry, basis, multiplicity, filename=filename) molecule.load() self.n_fermions = molecule.n_electrons self.n_orbitals = molecule.n_qubits # Get molecular Hamiltonian. self.molecular_hamiltonian = molecule.get_molecular_hamiltonian() self.fci_rdm = molecule.get_molecular_rdm(use_fci=1)
def load_and_transform(filename, orbitals, transform): # Load data print('--- Loading molecule ---') molecule = MolecularData(filename=filename) molecule.load() print('filename: {}'.format(molecule.filename)) print('n_atoms: {}'.format(molecule.n_atoms)) print('n_electrons: {}'.format(molecule.n_electrons)) print('n_orbitals: {}'.format(molecule.n_orbitals)) #print('Canonical Orbitals: {}'.format(molecule.canonical_orbitals)) print('n_qubits: {}'.format(molecule.n_qubits)) # Get the Hamiltonian in an active space. # Set Hamiltonian parameters. occupied_orbitals, active_orbitals = orbitals molecular_hamiltonian = molecule.get_molecular_hamiltonian( occupied_indices=range(occupied_orbitals), active_indices=range(active_orbitals)) # Map operator to fermions and qubits. fermion_hamiltonian = get_fermion_operator(molecular_hamiltonian) #print('Fermionic Hamiltonian is:\n{}'.format(fermion_hamiltonian)) if transform is 'JW': qubit_h = jordan_wigner(fermion_hamiltonian) qubit_h.compress() print('\nJordan-Wigner Hamiltonian:\n{}'.format(qubit_h)) elif transform is 'BK': qubit_h = bravyi_kitaev(fermion_hamiltonian) qubit_h.compress() print('\nBravyi-Kitaev Hamiltonian is:\n{}'.format(qubit_h)) else: print('ERROR: Unrecognized qubit transformation: {}'.format(transform)) sys.exit(2) return qubit_h
def test_rank_reduction(self): # Initialize H2. 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') molecule = MolecularData(geometry, basis, multiplicity, filename=filename) molecule.load() # Get molecular Hamiltonian. molecular_hamiltonian = molecule.get_molecular_hamiltonian() # Get fermion Hamiltonian. fermion_hamiltonian = normal_ordered( get_fermion_operator(molecular_hamiltonian)) # Get chemist tensor. constant, one_body_coefficients, chemist_tensor = ( get_chemist_two_body_coefficients(fermion_hamiltonian)) n_qubits = one_body_coefficients.shape[0] # Rank reduce with threshold. errors = [] for truncation_threshold in [1., 0.1, 0.01, 0.001]: # Add back one-body terms and constant. 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] decomposed_operator += FermionOperator(term, coefficient) # Rank reduce. eigenvalues, one_body_squares, trunc_error = ( low_rank_two_body_decomposition( chemist_tensor, truncation_threshold=truncation_threshold)) # Make sure error is below truncation specification. self.assertTrue(trunc_error < truncation_threshold) # Reassemble FermionOperator. l_max = eigenvalues.size for l in range(l_max): 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 - fermion_hamiltonian) errors += [difference.induced_norm()] self.assertTrue(errors[-1] <= trunc_error or abs(errors[-1] - trunc_error) < 1e-6) self.assertTrue(errors[3] <= errors[2] <= errors[1] <= errors[0]) # Rank reduce by setting final rank. errors = [] for final_rank in [4, 6, 8, 10, 12]: # Add back one-body terms and constant. 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] decomposed_operator += FermionOperator(term, coefficient) # Rank reduce. eigenvalues, one_body_squares, trunc_error = ( low_rank_two_body_decomposition(chemist_tensor, final_rank=final_rank)) # Reassemble FermionOperator. l_max = eigenvalues.size for l in range(l_max): 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 - fermion_hamiltonian) errors += [difference.induced_norm()] self.assertTrue(errors[3] <= errors[2] <= errors[1] <= errors[0])
class bravyi_kitaev_fastTransformTest(unittest.TestCase): 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 test_bad_input(self): with self.assertRaises(TypeError): _bksf.bravyi_kitaev_fast(FermionOperator()) def test_bravyi_kitaev_fast_edgeoperator_Bi(self): # checking the edge operators edge_matrix = numpy.triu(numpy.ones((4, 4))) edge_matrix_indices = numpy.array( numpy.nonzero( numpy.triu(edge_matrix) - numpy.diag(numpy.diag(edge_matrix)))) correct_operators_b0 = ((0, 'Z'), (1, 'Z'), (2, 'Z')) correct_operators_b1 = ((0, 'Z'), (3, 'Z'), (4, 'Z')) correct_operators_b2 = ((1, 'Z'), (3, 'Z'), (5, 'Z')) correct_operators_b3 = ((2, 'Z'), (4, 'Z'), (5, 'Z')) qterm_b0 = QubitOperator(correct_operators_b0, 1) qterm_b1 = QubitOperator(correct_operators_b1, 1) qterm_b2 = QubitOperator(correct_operators_b2, 1) qterm_b3 = QubitOperator(correct_operators_b3, 1) self.assertTrue( qterm_b0.isclose(_bksf.edge_operator_b(edge_matrix_indices, 0))) self.assertTrue( qterm_b1.isclose(_bksf.edge_operator_b(edge_matrix_indices, 1))) self.assertTrue( qterm_b2.isclose(_bksf.edge_operator_b(edge_matrix_indices, 2))) self.assertTrue( qterm_b3.isclose(_bksf.edge_operator_b(edge_matrix_indices, 3))) def test_bravyi_kitaev_fast_edgeoperator_Aij(self): # checking the edge operators edge_matrix = numpy.triu(numpy.ones((4, 4))) edge_matrix_indices = numpy.array( numpy.nonzero( numpy.triu(edge_matrix) - numpy.diag(numpy.diag(edge_matrix)))) correct_operators_a01 = ((0, 'X'), ) correct_operators_a02 = ((0, 'Z'), (1, 'X')) correct_operators_a03 = ((0, 'Z'), (1, 'Z'), (2, 'X')) correct_operators_a12 = ((0, 'Z'), (1, 'Z'), (3, 'X')) correct_operators_a13 = ((0, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'X')) correct_operators_a23 = ((1, 'Z'), (2, 'Z'), (3, 'Z'), (4, 'Z'), (5, 'X')) qterm_a01 = QubitOperator(correct_operators_a01, 1) qterm_a02 = QubitOperator(correct_operators_a02, 1) qterm_a03 = QubitOperator(correct_operators_a03, 1) qterm_a12 = QubitOperator(correct_operators_a12, 1) qterm_a13 = QubitOperator(correct_operators_a13, 1) qterm_a23 = QubitOperator(correct_operators_a23, 1) self.assertTrue( qterm_a01.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 0, 1))) self.assertTrue( qterm_a02.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 0, 2))) self.assertTrue( qterm_a03.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 0, 3))) self.assertTrue( qterm_a12.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 1, 2))) self.assertTrue( qterm_a13.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 1, 3))) self.assertTrue( qterm_a23.isclose( _bksf.edge_operator_aij(edge_matrix_indices, 2, 3))) def test_bravyi_kitaev_fast_jw_number_operator(self): # bksf algorithm allows for even number of particles. So, compare the # spectrum of number operator from jordan-wigner and bksf algorithm # to make sure half of the jordan-wigner number operator spectrum # can be found in bksf number operator spectrum. bravyi_kitaev_fast_n = _bksf.number_operator( self.molecular_hamiltonian) jw_n = QubitOperator() n_qubits = count_qubits(self.molecular_hamiltonian) for i in range(n_qubits): jw_n += jordan_wigner_one_body(i, i) jw_eig_spec = eigenspectrum(jw_n) bravyi_kitaev_fast_eig_spec = eigenspectrum(bravyi_kitaev_fast_n) evensector = 0 for i in range(numpy.size(jw_eig_spec)): if bool( numpy.size( numpy.where( jw_eig_spec[i] == bravyi_kitaev_fast_eig_spec))): evensector += 1 self.assertEqual(evensector, 2**(n_qubits - 1)) def test_bravyi_kitaev_fast_jw_hamiltonian(self): # make sure half of the jordan-wigner Hamiltonian eigenspectrum can # be found in bksf Hamiltonian eigenspectrum. n_qubits = count_qubits(self.molecular_hamiltonian) bravyi_kitaev_fast_H = _bksf.bravyi_kitaev_fast( self.molecular_hamiltonian) jw_H = jordan_wigner(self.molecular_hamiltonian) bravyi_kitaev_fast_H_eig = eigenspectrum(bravyi_kitaev_fast_H) jw_H_eig = eigenspectrum(jw_H) bravyi_kitaev_fast_H_eig = bravyi_kitaev_fast_H_eig.round(5) jw_H_eig = jw_H_eig.round(5) evensector = 0 for i in range(numpy.size(jw_H_eig)): if bool( numpy.size( numpy.where(jw_H_eig[i] == bravyi_kitaev_fast_H_eig))): evensector += 1 self.assertEqual(evensector, 2**(n_qubits - 1)) def test_bravyi_kitaev_fast_generate_fermions(self): # test for generating two fermions edge_matrix = _bksf.bravyi_kitaev_fast_edge_matrix( self.molecular_hamiltonian) edge_matrix_indices = numpy.array( numpy.nonzero( numpy.triu(edge_matrix) - numpy.diag(numpy.diag(edge_matrix)))) fermion_generation_operator = _bksf.generate_fermions( edge_matrix_indices, 2, 3) fermion_generation_sp_matrix = get_sparse_operator( fermion_generation_operator) fermion_generation_matrix = fermion_generation_sp_matrix.toarray() bksf_vacuum_state_operator = _bksf.vacuum_operator(edge_matrix_indices) bksf_vacuum_state_sp_matrix = get_sparse_operator( bksf_vacuum_state_operator) bksf_vacuum_state_matrix = bksf_vacuum_state_sp_matrix.toarray() vacuum_state = numpy.zeros((64, 1)) vacuum_state[0] = 1. bksf_vacuum_state = numpy.dot(bksf_vacuum_state_matrix, vacuum_state) two_fermion_state = numpy.dot(fermion_generation_matrix, bksf_vacuum_state) # using total number operator to check the number of fermions generated tot_number_operator = _bksf.number_operator(self.molecular_hamiltonian) number_operator_sp_matrix = get_sparse_operator(tot_number_operator) number_operator_matrix = number_operator_sp_matrix.toarray() tot_fermions = numpy.dot( two_fermion_state.conjugate().T, numpy.dot(number_operator_matrix, two_fermion_state)) # checking the occupation number of site 2 and 3 number_operator_2 = _bksf.number_operator(self.molecular_hamiltonian, 2) number_operator_3 = _bksf.number_operator(self.molecular_hamiltonian, 3) number_operator_23 = number_operator_2 + number_operator_3 number_operator_23_sp_matrix = get_sparse_operator(number_operator_23) number_operator_23_matrix = number_operator_23_sp_matrix.toarray() tot_23_fermions = numpy.dot( two_fermion_state.conjugate().T, numpy.dot(number_operator_23_matrix, two_fermion_state)) self.assertTrue(2.0 - float(tot_fermions.real) < 1e-13) self.assertTrue(2.0 - float(tot_23_fermions.real) < 1e-13) def test_bravyi_kitaev_fast_excitation_terms(self): # Testing on-site and excitation terms in Hamiltonian constant = 0 one_body = numpy.array([[1, 2, 0, 3], [2, 1, 2, 0], [0, 2, 1, 2.5], [3, 0, 2.5, 1]]) # No Coloumb interaction two_body = numpy.zeros((4, 4, 4, 4)) molecular_hamiltonian = InteractionOperator(constant, one_body, two_body) n_qubits = count_qubits(molecular_hamiltonian) # comparing the eigenspectrum of Hamiltonian bravyi_kitaev_fast_H = _bksf.bravyi_kitaev_fast(molecular_hamiltonian) jw_H = jordan_wigner(molecular_hamiltonian) bravyi_kitaev_fast_H_eig = eigenspectrum(bravyi_kitaev_fast_H) jw_H_eig = eigenspectrum(jw_H) bravyi_kitaev_fast_H_eig = bravyi_kitaev_fast_H_eig.round(5) jw_H_eig = jw_H_eig.round(5) evensector_H = 0 for i in range(numpy.size(jw_H_eig)): if bool( numpy.size( numpy.where(jw_H_eig[i] == bravyi_kitaev_fast_H_eig))): evensector_H += 1 # comparing eigenspectrum of number operator bravyi_kitaev_fast_n = _bksf.number_operator(molecular_hamiltonian) jw_n = QubitOperator() n_qubits = count_qubits(molecular_hamiltonian) for i in range(n_qubits): jw_n += jordan_wigner_one_body(i, i) jw_eig_spec = eigenspectrum(jw_n) bravyi_kitaev_fast_eig_spec = eigenspectrum(bravyi_kitaev_fast_n) evensector_n = 0 for i in range(numpy.size(jw_eig_spec)): if bool( numpy.size( numpy.where( jw_eig_spec[i] == bravyi_kitaev_fast_eig_spec))): evensector_n += 1 self.assertEqual(evensector_H, 2**(n_qubits - 1)) self.assertEqual(evensector_n, 2**(n_qubits - 1)) def test_bravyi_kitaev_fast_number_excitation_operator(self): # using hydrogen Hamiltonian and introducing some number operator terms constant = 0 one_body = numpy.zeros((4, 4)) one_body[(0, 0)] = .4 one_body[(1, 1)] = .5 one_body[(2, 2)] = .6 one_body[(3, 3)] = .7 two_body = self.molecular_hamiltonian.two_body_tensor # initiating number operator terms for all the possible cases two_body[(1, 2, 3, 1)] = 0.1 two_body[(1, 3, 2, 1)] = 0.1 two_body[(1, 2, 1, 3)] = 0.15 two_body[(3, 1, 2, 1)] = 0.15 two_body[(0, 2, 2, 1)] = 0.09 two_body[(1, 2, 2, 0)] = 0.09 two_body[(1, 2, 3, 2)] = 0.11 two_body[(2, 3, 2, 1)] = 0.11 two_body[(2, 2, 2, 2)] = 0.1 molecular_hamiltonian = InteractionOperator(constant, one_body, two_body) # comparing the eigenspectrum of Hamiltonian n_qubits = count_qubits(molecular_hamiltonian) bravyi_kitaev_fast_H = _bksf.bravyi_kitaev_fast(molecular_hamiltonian) jw_H = jordan_wigner(molecular_hamiltonian) bravyi_kitaev_fast_H_eig = eigenspectrum(bravyi_kitaev_fast_H) jw_H_eig = eigenspectrum(jw_H) bravyi_kitaev_fast_H_eig = bravyi_kitaev_fast_H_eig.round(5) jw_H_eig = jw_H_eig.round(5) evensector_H = 0 for i in range(numpy.size(jw_H_eig)): if bool( numpy.size( numpy.where(jw_H_eig[i] == bravyi_kitaev_fast_H_eig))): evensector_H += 1 # comparing eigenspectrum of number operator bravyi_kitaev_fast_n = _bksf.number_operator(molecular_hamiltonian) jw_n = QubitOperator() n_qubits = count_qubits(molecular_hamiltonian) for i in range(n_qubits): jw_n += jordan_wigner_one_body(i, i) jw_eig_spec = eigenspectrum(jw_n) bravyi_kitaev_fast_eig_spec = eigenspectrum(bravyi_kitaev_fast_n) evensector_n = 0 for i in range(numpy.size(jw_eig_spec)): if bool( numpy.size( numpy.where( jw_eig_spec[i] == bravyi_kitaev_fast_eig_spec))): evensector_n += 1 self.assertEqual(evensector_H, 2**(n_qubits - 1)) self.assertEqual(evensector_n, 2**(n_qubits - 1))
import scipy import scipy.linalg # Load saved file for LiH. diatomic_bond_length = 1.45 geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., diatomic_bond_length))] basis = 'sto-3g' multiplicity = 1 # Set Hamiltonian parameters. active_space_start = 1 active_space_stop = 3 # Generate and populate instance of MolecularData. molecule = MolecularData(geometry, basis, multiplicity, description="1.45") molecule.load() # Get the Hamiltonian in an active space. molecular_hamiltonian = molecule.get_molecular_hamiltonian( occupied_indices=range(active_space_start), active_indices=range(active_space_start, active_space_stop)) # Map operator to fermions and qubits. fermion_hamiltonian = get_fermion_operator(molecular_hamiltonian) qubit_hamiltonian = jordan_wigner(fermion_hamiltonian) qubit_hamiltonian.compress() print('The Jordan-Wigner Hamiltonian in canonical basis follows:\n{}'.format( qubit_hamiltonian)) # Get sparse operator and ground state energy. sparse_hamiltonian = get_sparse_operator(qubit_hamiltonian)
class UnitaryCC(unittest.TestCase): def test_uccsd_anti_hermitian(self): """Test operators are anti-Hermitian independent of inputs""" test_orbitals = 4 single_amplitudes = randn(*(test_orbitals, ) * 2) double_amplitudes = randn(*(test_orbitals, ) * 4) generator = uccsd_generator(single_amplitudes, double_amplitudes) conj_generator = hermitian_conjugated(generator) self.assertEqual(generator, -1. * conj_generator) def test_uccsd_singlet_anti_hermitian(self): """Test that the singlet version is anti-Hermitian""" test_orbitals = 8 test_electrons = 4 packed_amplitude_size = uccsd_singlet_paramsize( test_orbitals, test_electrons) packed_amplitudes = randn(int(packed_amplitude_size)) generator = uccsd_singlet_generator(packed_amplitudes, test_orbitals, test_electrons) conj_generator = hermitian_conjugated(generator) self.assertEqual(generator, -1. * conj_generator) def test_uccsd_singlet_symmetries(self): """Test that the singlet generator has the correct symmetries.""" test_orbitals = 8 test_electrons = 4 packed_amplitude_size = uccsd_singlet_paramsize( test_orbitals, test_electrons) packed_amplitudes = randn(int(packed_amplitude_size)) generator = uccsd_singlet_generator(packed_amplitudes, test_orbitals, test_electrons) # Construct symmetry operators sz = sz_operator(test_orbitals) s_squared = s_squared_operator(test_orbitals) # Check the symmetries comm_sz = normal_ordered(commutator(generator, sz)) comm_s_squared = normal_ordered(commutator(generator, s_squared)) zero = FermionOperator() self.assertEqual(comm_sz, zero) self.assertEqual(comm_s_squared, zero) def test_uccsd_singlet_builds(self): """Test specific builds of the UCCSD singlet operator""" # Build 1 n_orbitals = 4 n_electrons = 2 n_params = uccsd_singlet_paramsize(n_orbitals, n_electrons) self.assertEqual(n_params, 2) initial_amplitudes = [1., 2.] generator = uccsd_singlet_generator(initial_amplitudes, n_orbitals, n_electrons) test_generator = (FermionOperator("2^ 0", 1.) + FermionOperator("0^ 2", -1.) + FermionOperator("3^ 1", 1.) + FermionOperator("1^ 3", -1.) + FermionOperator("2^ 0 3^ 1", 4.) + FermionOperator("1^ 3 0^ 2", -4.)) self.assertEqual(normal_ordered(test_generator), normal_ordered(generator)) # Build 2 n_orbitals = 6 n_electrons = 2 n_params = uccsd_singlet_paramsize(n_orbitals, n_electrons) self.assertEqual(n_params, 5) initial_amplitudes = numpy.arange(1, n_params + 1, dtype=float) generator = uccsd_singlet_generator(initial_amplitudes, n_orbitals, n_electrons) test_generator = ( FermionOperator("2^ 0", 1.) + FermionOperator("0^ 2", -1) + FermionOperator("3^ 1", 1.) + FermionOperator("1^ 3", -1.) + FermionOperator("4^ 0", 2.) + FermionOperator("0^ 4", -2) + FermionOperator("5^ 1", 2.) + FermionOperator("1^ 5", -2.) + FermionOperator("2^ 0 3^ 1", 6.) + FermionOperator("1^ 3 0^ 2", -6.) + FermionOperator("4^ 0 5^ 1", 8.) + FermionOperator("1^ 5 0^ 4", -8.) + FermionOperator("2^ 0 5^ 1", 5.) + FermionOperator("1^ 5 0^ 2", -5.) + FermionOperator("4^ 0 3^ 1", 5.) + FermionOperator("1^ 3 0^ 4", -5.) + FermionOperator("2^ 0 4^ 0", 5.) + FermionOperator("0^ 4 0^ 2", -5.) + FermionOperator("3^ 1 5^ 1", 5.) + FermionOperator("1^ 5 1^ 3", -5.)) self.assertEqual(normal_ordered(test_generator), normal_ordered(generator)) def test_sparse_uccsd_generator_numpy_inputs(self): """Test numpy ndarray inputs to uccsd_generator 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_generator(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.assertEqual(test_generator, generator) def test_sparse_uccsd_generator_list_inputs(self): """Test list inputs to uccsd_generator that are sparse""" sparse_single_amplitudes = [[[3, 5], 0.12345], [[12, 4], 0.44313]] sparse_double_amplitudes = [[[0, 12, 6, 2], 0.3434], [[1, 4, 6, 13], -0.23423]] generator = uccsd_generator(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.assertEqual(test_generator, generator) def test_uccsd_singlet_get_packed_amplitudes(self): test_orbitals = 6 test_electrons = 2 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[2, 0] = 0.12345 sparse_single_amplitudes[3, 1] = 0.12345 sparse_double_amplitudes[2, 0, 3, 1] = 0.9 sparse_double_amplitudes[2, 0, 4, 0] = 0.3434 sparse_double_amplitudes[5, 1, 3, 1] = 0.3434 packed_amplitudes = uccsd_singlet_get_packed_amplitudes( sparse_single_amplitudes, sparse_double_amplitudes, test_orbitals, test_electrons) self.assertEqual(len(packed_amplitudes), 5) self.assertTrue( numpy.allclose(packed_amplitudes, numpy.array([0.12345, 0., 0.9, 0., 0.3434]))) def test_ucc_h2(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) # Test UCCSD for accuracy against FCI using loaded t amplitudes. ucc_operator = uccsd_generator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps) hf_state = jw_hartree_fock_state(self.molecule.n_electrons, count_qubits(self.qubit_hamiltonian)) uccsd_sparse = jordan_wigner_sparse(ucc_operator) uccsd_state = scipy.sparse.linalg.expm_multiply(uccsd_sparse, hf_state) expected_uccsd_energy = expectation(self.hamiltonian_matrix, uccsd_state) self.assertAlmostEqual(expected_uccsd_energy, self.molecule.fci_energy, places=4) print("UCCSD ENERGY: {}".format(expected_uccsd_energy)) # Test CCSD for precise match against FCI using loaded t amplitudes. ccsd_operator = uccsd_generator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps, anti_hermitian=False) ccsd_sparse_r = jordan_wigner_sparse(ccsd_operator) ccsd_sparse_l = jordan_wigner_sparse( -hermitian_conjugated(ccsd_operator)) ccsd_state_r = scipy.sparse.linalg.expm_multiply( ccsd_sparse_r, hf_state) ccsd_state_l = scipy.sparse.linalg.expm_multiply( ccsd_sparse_l, hf_state) expected_ccsd_energy = ccsd_state_l.conjugate().dot( self.hamiltonian_matrix.dot(ccsd_state_r)) self.assertAlmostEqual(expected_ccsd_energy, self.molecule.fci_energy) def test_ucc_h2_singlet(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) # Test UCCSD for accuracy against FCI using loaded t amplitudes. ucc_operator = uccsd_generator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps) hf_state = jw_hartree_fock_state(self.molecule.n_electrons, count_qubits(self.qubit_hamiltonian)) uccsd_sparse = jordan_wigner_sparse(ucc_operator) uccsd_state = scipy.sparse.linalg.expm_multiply(uccsd_sparse, hf_state) expected_uccsd_energy = expectation(self.hamiltonian_matrix, uccsd_state) self.assertAlmostEqual(expected_uccsd_energy, self.molecule.fci_energy, places=4) print("UCCSD ENERGY: {}".format(expected_uccsd_energy)) # Test CCSD singlet for precise match against FCI using loaded t # amplitudes packed_amplitudes = uccsd_singlet_get_packed_amplitudes( self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps, self.molecule.n_qubits, self.molecule.n_electrons) ccsd_operator = uccsd_singlet_generator(packed_amplitudes, self.molecule.n_qubits, self.molecule.n_electrons, anti_hermitian=False) ccsd_sparse_r = jordan_wigner_sparse(ccsd_operator) ccsd_sparse_l = jordan_wigner_sparse( -hermitian_conjugated(ccsd_operator)) ccsd_state_r = scipy.sparse.linalg.expm_multiply( ccsd_sparse_r, hf_state) ccsd_state_l = scipy.sparse.linalg.expm_multiply( ccsd_sparse_l, hf_state) expected_ccsd_energy = ccsd_state_l.conjugate().dot( self.hamiltonian_matrix.dot(ccsd_state_r)) self.assertAlmostEqual(expected_ccsd_energy, self.molecule.fci_energy) def test_value_error_for_odd_n_qubits(self): # Pass odd n_qubits to singlet generators with self.assertRaises(ValueError): _ = uccsd_singlet_paramsize(3, 4) def test_value_error_bad_amplitudes(self): with self.assertRaises(ValueError): _ = uccsd_singlet_generator([1.], 3, 4)
def make_molecular_energy_obj(molecule_name, basis="sto-3g", geometry_info=None, n_cancel_orbital=0, n_frozen_orbital=0, cas_irrep_nocc=None, cas_irrep_ncore=None, fermi_qubit_transform=bravyi_kitaev, is_computed=False): if geometry_info == None: geometry_info = equilibrium_geometry_dict[molecule_name] # Get geometry if molecule_name not in geometry_generator_dict.keys(): print("No such example molecule, using default H2 hamiltonian.") molecule_name = "H2" geometry = geometry_generator_dict[molecule_name](geometry_info) # Get fermion Hamiltonian multiplicity = 1 charge = 0 molecule = MolecularData(geometry, basis, multiplicity, charge, str(geometry_info)) molecule.symmetry = True if not is_computed: molecule = run_pyscf(molecule, run_fci=1, n_frozen_orbital=n_frozen_orbital, n_cancel_orbital=n_cancel_orbital, cas_irrep_nocc=cas_irrep_nocc, cas_irrep_ncore=cas_irrep_ncore, verbose=False) molecule.load() active_space_start = n_frozen_orbital active_space_stop = molecule.n_orbitals - n_cancel_orbital n_active_orb = active_space_stop - active_space_start molecule.n_orbitals = n_active_orb molecule.n_qubits = n_active_orb * 2 molecule.n_electrons = molecule.n_electrons - active_space_start * 2 fermion_hamiltonian = get_fermion_operator( molecule.get_molecular_hamiltonian( occupied_indices=molecule.frozen_orbitals, active_indices=molecule.active_orbitals)) # Map ferimon Hamiltonian to qubit Hamiltonian qubit_hamiltonian = fermi_qubit_transform(fermion_hamiltonian) # qubit_electron_operator=fermi_qubit_transform(get_electron_fermion_operator(molecule.n_electrons)) qubit_electron_operator = get_HF_operator(molecule.n_electrons, fermi_qubit_transform) # qubit_hamiltonian=get_dressed_operator(qubit_electron_operator,qubit_hamiltonian) # Ignore terms in Hamiltonian that close to zero qubit_hamiltonian.compress() # Set the terminate_energy to be achieving the chemical accuracy terminate_energy = molecule.fci_energy + CHEMICAL_ACCURACY obj_info = { "n_qubit": molecule.n_qubits, "start_cost": molecule.hf_energy, "terminate_cost": terminate_energy } init_operator = HartreeFockInitBlock( get_operator_qsubset(qubit_electron_operator)) return EnergyObjective(qubit_hamiltonian, molecule.n_qubits, init_operator, obj_info)
class UnitaryCC(unittest.TestCase): def test_uccsd_anti_hermitian(self): """Test operators are anti-Hermitian independent of inputs""" test_orbitals = 4 single_amplitudes = randn(*(test_orbitals, ) * 2) double_amplitudes = randn(*(test_orbitals, ) * 4) generator = uccsd_operator(single_amplitudes, double_amplitudes) conj_generator = hermitian_conjugated(generator) self.assertTrue(generator.isclose(-1. * conj_generator)) def test_uccsd_singlet_anti_hermitian(self): """Test that the singlet version is anti-Hermitian""" test_orbitals = 8 test_electrons = 4 packed_amplitude_size = uccsd_singlet_paramsize( test_orbitals, test_electrons) packed_amplitudes = randn(int(packed_amplitude_size)) generator = uccsd_singlet_operator(packed_amplitudes, test_orbitals, test_electrons) conj_generator = hermitian_conjugated(generator) self.assertTrue(generator.isclose(-1. * conj_generator)) def test_uccsd_singlet_build(self): """Test a specific build of the UCCSD singlet operator""" initial_amplitudes = [-1.14941450e-08, 5.65340614e-02] n_orbitals = 4 n_electrons = 2 generator = uccsd_singlet_operator(initial_amplitudes, n_orbitals, n_electrons) test_generator = (0.0565340614 * FermionOperator("2^ 0 3^ 1") + 1.1494145e-08 * FermionOperator("1^ 3") + 0.0565340614 * FermionOperator("3^ 1 2^ 0") + 0.0565340614 * FermionOperator("2^ 0 2^ 0") + 1.1494145e-08 * FermionOperator("0^ 2") + (-0.0565340614) * FermionOperator("1^ 3 0^ 2") + (-1.1494145e-08) * FermionOperator("3^ 1") + (-0.0565340614) * FermionOperator("1^ 3 1^ 3") + (-0.0565340614) * FermionOperator("0^ 2 0^ 2") + (-1.1494145e-08) * FermionOperator("2^ 0") + 0.0565340614 * FermionOperator("3^ 1 3^ 1") + (-0.0565340614) * FermionOperator("0^ 2 1^ 3")) self.assertTrue(test_generator.isclose(generator)) 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_sparse_uccsd_operator_list_inputs(self): """Test list inputs to uccsd_operator that are sparse""" sparse_single_amplitudes = [[[3, 5], 0.12345], [[12, 4], 0.44313]] sparse_double_amplitudes = [[[0, 12, 6, 2], 0.3434], [[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_ucc(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) # Test UCCSD for accuracy against FCI using loaded t amplitudes. ucc_operator = uccsd_operator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps) hf_state = jw_hartree_fock_state(self.molecule.n_electrons, count_qubits(self.qubit_hamiltonian)) uccsd_sparse = jordan_wigner_sparse(ucc_operator) uccsd_state = scipy.sparse.linalg.expm_multiply(uccsd_sparse, hf_state) expected_uccsd_energy = expectation(self.hamiltonian_matrix, uccsd_state) self.assertAlmostEqual(expected_uccsd_energy, self.molecule.fci_energy, places=4) print("UCCSD ENERGY: {}".format(expected_uccsd_energy)) # Test CCSD for precise match against FCI using loaded t amplitudes. ccsd_operator = uccsd_operator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps, anti_hermitian=False) ccsd_sparse_r = jordan_wigner_sparse(ccsd_operator) ccsd_sparse_l = jordan_wigner_sparse( -hermitian_conjugated(ccsd_operator)) # Test CCSD for precise match against FCI using loaded t amplitudes ccsd_operator = uccsd_operator(self.molecule.ccsd_single_amps, self.molecule.ccsd_double_amps, anti_hermitian=False) ccsd_sparse_r = jordan_wigner_sparse(ccsd_operator) ccsd_sparse_l = jordan_wigner_sparse( -hermitian_conjugated(ccsd_operator)) ccsd_state_r = scipy.sparse.linalg.expm_multiply( ccsd_sparse_r, hf_state) ccsd_state_l = scipy.sparse.linalg.expm_multiply( ccsd_sparse_l, hf_state) expected_ccsd_energy = ccsd_state_l.getH().dot( self.hamiltonian_matrix.dot(ccsd_state_r))[0, 0] self.assertAlmostEqual(expected_ccsd_energy, self.molecule.fci_energy)