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 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 test_lih_tpdm_ab_build(): """ Check if 2-RDM construction from pauli terms works for the ab block """ lih_file = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5") molecule = MolecularData(filename=lih_file) rdms = molecule.get_molecular_rdm(use_fci=True) dim = molecule.n_qubits d2aa, d2bb, d2ab = get_sz_spin_adapted(molecule.fci_two_rdm) paulis_to_measure = pauli_terms_for_tpdm_ab(dim // 2) pauli_to_coeff = {} for term in paulis_to_measure: # convert back to FermionOperator qubit_op = pyquilpauli_to_qubitop(term_with_coeff(term, 1.0)) pauli_to_coeff[term.id()] = rdms.expectation(qubit_op) tpdm_ab = pauli_to_tpdm_ab(dim // 2, pauli_to_coeff) assert np.allclose(tpdm_ab, d2ab)
def test_h2_tpdm_build(): """ Check if constructing the 2-RDM (full) works. This check uses openfermion data and thus requires openfermion to be installed """ h2_file = os.path.join(DATA_DIRECTORY, "H2_sto-3g_singlet_0.7.hdf5") molecule = MolecularData(filename=h2_file) rdms = molecule.get_molecular_rdm(use_fci=True) dim = molecule.n_qubits paulis_to_measure = pauli_terms_for_tpdm(dim) pauli_to_coeff = {} for term in paulis_to_measure: # convert back to FermionOperator qubit_op = pyquilpauli_to_qubitop(term_with_coeff(term, 1.0)) pauli_to_coeff[term.id()] = rdms.expectation(qubit_op) tpdm = pauli_to_tpdm(dim, pauli_to_coeff) assert np.allclose(tpdm, molecule.fci_two_rdm)
def test_h2_spin_adapted_ab(): h2_file = os.path.join(DATA_DIRECTORY, "H2_sto-3g_singlet_0.7.hdf5") molecule = MolecularData(filename=h2_file) rdms = molecule.get_molecular_rdm(use_fci=True) dim = molecule.n_qubits paulis_to_measure = pauli_terms_for_tpdm(dim) pauli_to_coeff = {} for term in paulis_to_measure: # convert back to FermionOperator qubit_op = pyquilpauli_to_qubitop(term_with_coeff(term, 1.0)) pauli_to_coeff[term.id()] = rdms.expectation(qubit_op) tpdm = pauli_to_tpdm(dim, pauli_to_coeff) d2aa, d2bb, d2ab = get_sz_spin_adapted(tpdm) paulis_to_measure_ab = pauli_terms_for_tpdm_ab(dim // 2) pauli_to_coeff = {} for term in paulis_to_measure_ab: # convert back to FermionOperator qubit_op = pyquilpauli_to_qubitop(term_with_coeff(term, 1.0)) pauli_to_coeff[term.id()] = rdms.expectation(qubit_op) tpdm_ab = pauli_to_tpdm_ab(dim // 2, pauli_to_coeff) assert np.allclose(d2ab, tpdm_ab)
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))
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)
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)