def setUp(self): self.geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] self.basis = 'sto-3g' self.multiplicity = 1 self.filename = os.path.join(DATA_DIRECTORY, 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) self.molecule.load()
def test_name_molecule(self): charge = 0 correct_name = str('H2_sto-3g_singlet_0.7414') computed_name = name_molecule(self.geometry, self.basis, self.multiplicity, charge, description="0.7414") self.assertEqual(correct_name, computed_name) self.assertEqual(correct_name, self.molecule.name) # Check (+) charge charge = 1 correct_name = "H2_sto-3g_singlet_1+_0.7414" computed_name = name_molecule(self.geometry, self.basis, self.multiplicity, charge, description="0.7414") self.assertEqual(correct_name, computed_name) # Check > 1 atom type charge = 0 correct_name = "H1-F1_sto-3g_singlet_1.0" test_geometry = [('H', (0, 0, 0)), ('F', (0, 0, 1.0))] computed_name = name_molecule(test_geometry, self.basis, self.multiplicity, charge, description="1.0") self.assertEqual(correct_name, computed_name) # Check errors in naming with self.assertRaises(TypeError): test_molecule = MolecularData(self.geometry, self.basis, self.multiplicity, description=5) correct_name = str('H2_sto-3g_singlet') test_molecule = self.molecule = MolecularData( self.geometry, self.basis, self.multiplicity, data_directory=DATA_DIRECTORY) self.assertSequenceEqual(correct_name, test_molecule.name)
class IntegralTransformsTest(unittest.TestCase): def setUp(self): self.geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] self.basis = 'sto-3g' self.multiplicity = 1 self.filename = os.path.join(DATA_DIRECTORY, 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) self.molecule.load() def test_integrals_self_inverse(self): hc, hr1, hr2 = get_doci_from_integrals( self.molecule.one_body_integrals, self.molecule.two_body_integrals) proj_one_body, proj_two_body = get_projected_integrals_from_doci( hc, hr1, hr2) hc_test, hr1_test, hr2_test = get_doci_from_integrals( proj_one_body, proj_two_body) self.assertTrue(numpy.allclose(hc, hc_test)) self.assertTrue(numpy.allclose(hr1, hr1_test)) print(hr2) print(hr2_test) self.assertTrue(numpy.allclose(hr2, hr2_test)) def test_integrals_to_doci(self): one_body_integrals = self.molecule.one_body_integrals two_body_integrals = self.molecule.two_body_integrals hc, hr1, hr2 = get_doci_from_integrals(one_body_integrals, two_body_integrals) self.assertEqual(hc.shape[0], 2) self.assertEqual(hr1.shape[0], 2) self.assertEqual(hr2.shape[0], 2) for p in range(2): self.assertEqual( hc[p] + hr2[p, p], 2 * one_body_integrals[p, p] + two_body_integrals[p, p, p, p]) for q in range(2): if p != q: self.assertEqual(hr1[p, q], two_body_integrals[p, p, q, q]) self.assertEqual( hr2[p, q], 2 * two_body_integrals[p, q, q, p] - two_body_integrals[p, q, p, q])
def test_missing_calcs_for_integrals(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.8764))] basis = 'sto-3g' multiplicity = 1 molecule = MolecularData(geometry, basis, multiplicity) with self.assertRaises(MissingCalculationError): molecule.get_j() with self.assertRaises(MissingCalculationError): molecule.get_k() with self.assertRaises(MissingCalculationError): molecule.get_antisym()
def test_file_loads(self): """Test different filename specs""" data_directory = os.path.join(DATA_DIRECTORY) molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) test_hf_energy = molecule.hf_energy molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename + ".hdf5", data_directory=data_directory) self.assertAlmostEqual(test_hf_energy, molecule.hf_energy) molecule = MolecularData(filename=self.filename + ".hdf5") integrals = molecule.one_body_integrals self.assertTrue(integrals is not None) with self.assertRaises(ValueError): MolecularData()
def make_atom(atom_type, basis, filename=''): """Prepare a molecular data instance for a single element. Args: atom_type: Float giving atomic symbol. basis: The basis in which to perform the calculation. Returns: atom: An instance of the MolecularData class. """ geometry = [(atom_type, (0., 0., 0.))] atomic_number = periodic_hash_table[atom_type] spin = periodic_polarization[atomic_number] / 2. multiplicity = int(2 * spin + 1) atom = MolecularData(geometry, basis, multiplicity, filename=filename) return atom
def make_atomic_ring(n_atoms, spacing, basis, atom_type='H', charge=0, filename=''): """Function to create atomic rings with n_atoms. Note that basic geometry suggests that for spacing L between atoms the radius of the ring should be L / (2 * cos (pi / 2 - theta / 2)) Args: n_atoms: Integer, the number of atoms in the ring. spacing: The spacing between atoms in the ring in Angstroms. basis: The basis in which to perform the calculation. atom_type: String, the atomic symbol of the element in the ring. this defaults to 'H' for Hydrogen. charge: An integer giving the total molecular charge. Defaults to 0. filename: An optional string to give a filename for the molecule. Returns: molecule: A an instance of the MolecularData class. """ # Make geometry. geometry = [] theta = 2. * numpy.pi / float(n_atoms) radius = spacing / (2. * numpy.cos(numpy.pi / 2. - theta / 2.)) for atom in range(n_atoms): x_coord = radius * numpy.cos(atom * theta) y_coord = radius * numpy.sin(atom * theta) geometry += [(atom_type, (x_coord, y_coord, 0.))] # Set multiplicity. n_electrons = n_atoms * periodic_hash_table[atom_type] n_electrons -= charge if (n_electrons % 2): multiplicity = 2 else: multiplicity = 1 # Create molecule and return. description = 'ring_{}'.format(spacing) molecule = MolecularData(geometry, basis, multiplicity, charge, description, filename) return molecule
def test_invalid_multiplicity(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = 'sto-3g' multiplicity = -1 with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity)
class MolecularDataTest(unittest.TestCase): def setUp(self): self.geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] self.basis = 'sto-3g' self.multiplicity = 1 self.filename = os.path.join(DATA_DIRECTORY, 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) self.molecule.load() def testUnitConversion(self): """Test the unit conversion routines""" unit_angstrom = 1.0 bohr = angstroms_to_bohr(unit_angstrom) self.assertAlmostEqual(bohr, 1.889726) inverse_transform = bohr_to_angstroms(bohr) self.assertAlmostEqual(inverse_transform, 1.0) def test_name_molecule(self): charge = 0 correct_name = str('H2_sto-3g_singlet_0.7414') computed_name = name_molecule(self.geometry, self.basis, self.multiplicity, charge, description="0.7414") self.assertEqual(correct_name, computed_name) self.assertEqual(correct_name, self.molecule.name) # Check (+) charge charge = 1 correct_name = "H2_sto-3g_singlet_1+_0.7414" computed_name = name_molecule(self.geometry, self.basis, self.multiplicity, charge, description="0.7414") self.assertEqual(correct_name, computed_name) # Check > 1 atom type charge = 0 correct_name = "H1-F1_sto-3g_singlet_1.0" test_geometry = [('H', (0, 0, 0)), ('F', (0, 0, 1.0))] computed_name = name_molecule(test_geometry, self.basis, self.multiplicity, charge, description="1.0") self.assertEqual(correct_name, computed_name) # Check errors in naming with self.assertRaises(TypeError): test_molecule = MolecularData(self.geometry, self.basis, self.multiplicity, description=5) correct_name = str('H2_sto-3g_singlet') test_molecule = self.molecule = MolecularData( self.geometry, self.basis, self.multiplicity, data_directory=DATA_DIRECTORY) self.assertSequenceEqual(correct_name, test_molecule.name) def test_invalid_multiplicity(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = 'sto-3g' multiplicity = -1 with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity) def test_geometry_from_file(self): water_geometry = [('O', (0., 0., 0.)), ('H', (0.757, 0.586, 0.)), ('H', (-.757, 0.586, 0.))] filename = os.path.join(DATA_DIRECTORY, 'geometry_example.txt') test_geometry = geometry_from_file(filename) for atom in range(3): self.assertAlmostEqual(water_geometry[atom][0], test_geometry[atom][0]) for coordinate in range(3): self.assertAlmostEqual(water_geometry[atom][1][coordinate], test_geometry[atom][1][coordinate]) def test_save_load(self): n_atoms = self.molecule.n_atoms orbitals = self.molecule.canonical_orbitals self.assertFalse(orbitals is None) self.molecule.n_atoms += 1 self.assertEqual(self.molecule.n_atoms, n_atoms + 1) self.molecule.load() self.assertEqual(self.molecule.n_atoms, n_atoms) dummy_data = self.molecule.get_from_file("dummy_entry") self.assertTrue(dummy_data is None) def test_dummy_save(self): # Make fake molecule. filename = os.path.join(DATA_DIRECTORY, 'dummy_molecule') geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = '6-31g*' multiplicity = 7 charge = -1 description = 'openfermion_forever' molecule = MolecularData(geometry, basis, multiplicity, charge, description, filename) # Make some attributes to save. molecule.n_orbitals = 10 molecule.n_qubits = 10 molecule.nuclear_repulsion = -12.3 molecule.hf_energy = 99. molecule.canonical_orbitals = [1, 2, 3, 4] molecule.orbital_energies = [5, 6, 7, 8] molecule.one_body_integrals = [5, 6, 7, 8] molecule.two_body_integrals = [5, 6, 7, 8] molecule.mp2_energy = -12. molecule.cisd_energy = 32. molecule.cisd_one_rdm = numpy.arange(10) molecule.cisd_two_rdm = numpy.arange(10) molecule.fci_energy = 232. molecule.fci_one_rdm = numpy.arange(11) molecule.fci_two_rdm = numpy.arange(11) molecule.ccsd_energy = 88. molecule.ccsd_single_amps = [1, 2, 3] molecule.ccsd_double_amps = [1, 2, 3] molecule.general_calculations['Fake CI'] = 1.2345 molecule.general_calculations['Fake CI 2'] = 5.2345 # Test missing calculation and information exceptions molecule.one_body_integrals = None with self.assertRaises(MissingCalculationError): molecule.get_integrals() molecule.hf_energy = 99. with self.assertRaises(ValueError): molecule.get_active_space_integrals([], []) molecule.fci_energy = None with self.assertRaises(MissingCalculationError): molecule.get_molecular_rdm(use_fci=True) molecule.fci_energy = 232. molecule.cisd_energy = None with self.assertRaises(MissingCalculationError): molecule.get_molecular_rdm(use_fci=False) molecule.cisd_energy = 232. # Save molecule. molecule.save() try: # Change attributes and load. molecule.ccsd_energy = -2.232 # Load molecule. new_molecule = MolecularData(filename=filename) molecule.general_calculations = {} molecule.load() self.assertEqual(molecule.general_calculations['Fake CI'], 1.2345) # Tests re-load functionality molecule.save() # Check CCSD energy. self.assertAlmostEqual(new_molecule.ccsd_energy, molecule.ccsd_energy) self.assertAlmostEqual(molecule.ccsd_energy, 88.) finally: os.remove(filename + '.hdf5') def test_file_loads(self): """Test different filename specs""" data_directory = os.path.join(DATA_DIRECTORY) molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) test_hf_energy = molecule.hf_energy molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename + ".hdf5", data_directory=data_directory) self.assertAlmostEqual(test_hf_energy, molecule.hf_energy) molecule = MolecularData(filename=self.filename + ".hdf5") integrals = molecule.one_body_integrals self.assertTrue(integrals is not None) with self.assertRaises(ValueError): MolecularData() def test_active_space(self): """Test simple active space truncation features""" # Start w/ no truncation core_const, one_body_integrals, two_body_integrals = ( self.molecule.get_active_space_integrals(active_indices=[0, 1])) self.assertAlmostEqual(core_const, 0.0) self.assertAlmostEqual( scipy.linalg.norm(one_body_integrals - self.molecule.one_body_integrals), 0.0) self.assertAlmostEqual( scipy.linalg.norm(two_body_integrals - self.molecule.two_body_integrals), 0.0) def test_energies(self): self.assertAlmostEqual(self.molecule.hf_energy, -1.1167, places=4) self.assertAlmostEqual(self.molecule.mp2_energy, -1.1299, places=4) self.assertAlmostEqual(self.molecule.cisd_energy, -1.1373, places=4) self.assertAlmostEqual(self.molecule.ccsd_energy, -1.1373, places=4) self.assertAlmostEqual(self.molecule.ccsd_energy, -1.1373, places=4) def test_rdm_and_rotation(self): # Compute total energy from RDM. molecular_hamiltonian = self.molecule.get_molecular_hamiltonian() molecular_rdm = self.molecule.get_molecular_rdm() total_energy = molecular_rdm.expectation(molecular_hamiltonian) self.assertAlmostEqual(total_energy, self.molecule.cisd_energy) # Build random rotation with correction dimension. num_spatial_orbitals = self.molecule.n_orbitals rotation_generator = numpy.random.randn(num_spatial_orbitals, num_spatial_orbitals) rotation_matrix = scipy.linalg.expm(rotation_generator - rotation_generator.T) # Compute total energy from RDM under some basis set rotation. molecular_rdm.rotate_basis(rotation_matrix) molecular_hamiltonian.rotate_basis(rotation_matrix) total_energy = molecular_rdm.expectation(molecular_hamiltonian) self.assertAlmostEqual(total_energy, self.molecule.cisd_energy) def test_get_up_down_electrons(self): largest_atom = 10 # Test first row correct_alpha = [0, 1, 1, 2, 2, 3, 4, 5, 5, 5, 5] correct_beta = [0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 5] for n_electrons in range(1, largest_atom + 1): # Make molecule. basis = 'sto-3g' atom_name = periodic_table[n_electrons] molecule = make_atom(atom_name, basis) # Test. self.assertAlmostEqual(molecule.get_n_alpha_electrons(), correct_alpha[n_electrons]) self.assertAlmostEqual(molecule.get_n_beta_electrons(), correct_beta[n_electrons]) def test_abstract_molecule(self): """Test an abstract molecule like jellium for saving and loading""" jellium_interaction = get_interaction_operator( jellium_model(Grid(2, 2, 1.0))) jellium_molecule = get_molecular_data(jellium_interaction, geometry="Jellium", basis="PlaneWave22", multiplicity=1, n_electrons=4) jellium_filename = jellium_molecule.filename jellium_molecule.save() jellium_molecule.load() correct_name = "Jellium_PlaneWave22_singlet" self.assertEqual(jellium_molecule.name, correct_name) os.remove("{}.hdf5".format(jellium_filename)) def test_load_molecular_hamiltonian(self): bond_length = 1.45 geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., bond_length))] lih_hamiltonian = load_molecular_hamiltonian(geometry, 'sto-3g', 1, format(bond_length), 2, 2) self.assertEqual(count_qubits(lih_hamiltonian), 4) lih_hamiltonian = load_molecular_hamiltonian(geometry, 'sto-3g', 1, format(bond_length), 2, 3) self.assertEqual(count_qubits(lih_hamiltonian), 6) lih_hamiltonian = load_molecular_hamiltonian(geometry, 'sto-3g', 1, format(bond_length), None, None) self.assertEqual(count_qubits(lih_hamiltonian), 12) def test_jk_matr(self): h2mol = self.molecule j = h2mol.get_j() k = h2mol.get_k() pyscf_j = [[0.67448877, 0.6634681], [0.6634681, 0.69739377]] pyscf_k = [[0.67448877, 0.18128881], [0.18128881, 0.69739377]] for p in range(j.shape[0]): for q in range(j.shape[1]): self.assertAlmostEqual(j[p][q], pyscf_j[p][q]) self.assertAlmostEqual(k[p][q], pyscf_k[p][q]) ndocc = h2mol.n_electrons // 2 E1bdy = 2 * h2mol.one_body_integrals[:ndocc, :ndocc] E2bdy = (2 * j[:ndocc, :ndocc]) - k[:ndocc, :ndocc] E_test = h2mol.nuclear_repulsion + E1bdy + E2bdy self.assertAlmostEqual(E_test, h2mol.hf_energy) def test_antisymint(self): h2mol = self.molecule antisymm_spin_orb_tei = h2mol.get_antisym() nocc = h2mol.n_electrons mol_H = h2mol.get_molecular_hamiltonian() E1bdy = np.sum(np.diag(mol_H.one_body_tensor[:nocc, :nocc])) E2bdy = 1/2.*np.einsum('ijij',\ antisymm_spin_orb_tei[:nocc,:nocc,:nocc,:nocc]) E_test = h2mol.nuclear_repulsion + E1bdy + E2bdy self.assertAlmostEqual(E_test, h2mol.hf_energy) def test_missing_calcs_for_integrals(self): geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.8764))] basis = 'sto-3g' multiplicity = 1 molecule = MolecularData(geometry, basis, multiplicity) with self.assertRaises(MissingCalculationError): molecule.get_j() with self.assertRaises(MissingCalculationError): molecule.get_k() with self.assertRaises(MissingCalculationError): molecule.get_antisym()
def test_dummy_save(self): # Make fake molecule. filename = os.path.join(DATA_DIRECTORY, 'dummy_molecule') geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] basis = '6-31g*' multiplicity = 7 charge = -1 description = 'openfermion_forever' molecule = MolecularData(geometry, basis, multiplicity, charge, description, filename) # Make some attributes to save. molecule.n_orbitals = 10 molecule.n_qubits = 10 molecule.nuclear_repulsion = -12.3 molecule.hf_energy = 99. molecule.canonical_orbitals = [1, 2, 3, 4] molecule.orbital_energies = [5, 6, 7, 8] molecule.one_body_integrals = [5, 6, 7, 8] molecule.two_body_integrals = [5, 6, 7, 8] molecule.mp2_energy = -12. molecule.cisd_energy = 32. molecule.cisd_one_rdm = numpy.arange(10) molecule.cisd_two_rdm = numpy.arange(10) molecule.fci_energy = 232. molecule.fci_one_rdm = numpy.arange(11) molecule.fci_two_rdm = numpy.arange(11) molecule.ccsd_energy = 88. molecule.ccsd_single_amps = [1, 2, 3] molecule.ccsd_double_amps = [1, 2, 3] molecule.general_calculations['Fake CI'] = 1.2345 molecule.general_calculations['Fake CI 2'] = 5.2345 # Test missing calculation and information exceptions molecule.one_body_integrals = None with self.assertRaises(MissingCalculationError): molecule.get_integrals() molecule.hf_energy = 99. with self.assertRaises(ValueError): molecule.get_active_space_integrals([], []) molecule.fci_energy = None with self.assertRaises(MissingCalculationError): molecule.get_molecular_rdm(use_fci=True) molecule.fci_energy = 232. molecule.cisd_energy = None with self.assertRaises(MissingCalculationError): molecule.get_molecular_rdm(use_fci=False) molecule.cisd_energy = 232. # Save molecule. molecule.save() try: # Change attributes and load. molecule.ccsd_energy = -2.232 # Load molecule. new_molecule = MolecularData(filename=filename) molecule.general_calculations = {} molecule.load() self.assertEqual(molecule.general_calculations['Fake CI'], 1.2345) # Tests re-load functionality molecule.save() # Check CCSD energy. self.assertAlmostEqual(new_molecule.ccsd_energy, molecule.ccsd_energy) self.assertAlmostEqual(molecule.ccsd_energy, 88.) finally: os.remove(filename + '.hdf5')
class IntegralTransformsTest(unittest.TestCase): def setUp(self): self.geometry = [('H', (0., 0., 0.)), ('Li', (0., 0., 1.45))] self.basis = 'sto-3g' self.multiplicity = 1 self.filename = os.path.join(DATA_DIRECTORY, 'H1-Li1_sto-3g_singlet_1.45') self.molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) self.molecule.load() def test_integrals_self_inverse(self): hc, hr1, hr2 = get_doci_from_integrals( self.molecule.one_body_integrals, self.molecule.two_body_integrals) doci = DOCIHamiltonian(0, hc, hr1, hr2) proj_one_body, proj_two_body = doci.get_projected_integrals() hc_test, hr1_test, hr2_test = get_doci_from_integrals( proj_one_body, proj_two_body) self.assertTrue(numpy.allclose(hc, hc_test)) self.assertTrue(numpy.allclose(hr1, hr1_test)) self.assertTrue(numpy.allclose(hr2, hr2_test)) def test_fermionic_hamiltonian_from_integrals(self): constant = self.molecule.nuclear_repulsion doci_constant = constant hc, hr1, hr2 = get_doci_from_integrals( self.molecule.one_body_integrals, self.molecule.two_body_integrals) doci = DOCIHamiltonian(doci_constant, hc, hr1, hr2) doci_qubit_op = doci.qubit_operator doci_mat = get_sparse_operator(doci_qubit_op).toarray() #doci_eigvals, doci_eigvecs = numpy.linalg.eigh(doci_mat) doci_eigvals, _ = numpy.linalg.eigh(doci_mat) tensors = doci.n_body_tensors one_body_tensors, two_body_tensors = tensors[(1, 0)], tensors[(1, 1, 0, 0)] fermion_op1 = get_fermion_operator( InteractionOperator(constant, one_body_tensors, 0. * two_body_tensors)) fermion_op2 = get_fermion_operator( InteractionOperator(0, 0 * one_body_tensors, 0.5 * two_body_tensors)) import openfermion as of fermion_op1_jw = of.transforms.jordan_wigner(fermion_op1) fermion_op2_jw = of.transforms.jordan_wigner(fermion_op2) fermion_op_jw = fermion_op1_jw + fermion_op2_jw #fermion_eigvals, fermion_eigvecs = numpy.linalg.eigh( # get_sparse_operator(fermion_op_jw).toarray()) fermion_eigvals, _ = numpy.linalg.eigh( get_sparse_operator(fermion_op_jw).toarray()) for eigval in doci_eigvals: assert any(abs(fermion_eigvals - eigval) < 1e-6), "The DOCI spectrum should \ have been contained in the spectrum of the fermionic operators" fermion_diagonal = get_sparse_operator( fermion_op_jw).toarray().diagonal() qubit_diagonal = doci_mat.diagonal() assert numpy.isclose( fermion_diagonal[0], qubit_diagonal[0] ) and numpy.isclose( fermion_diagonal[-1], qubit_diagonal[-1] ), "The first and last elements of hte qubit and fermionic diagonal of \ the Hamiltonian maxtrix should be the same as the vaccum should be \ mapped to the computational all zero state and the completely filled \ state should be mapped to the all one state" print(fermion_diagonal) print(qubit_diagonal) def test_integrals_to_doci(self): one_body_integrals = self.molecule.one_body_integrals two_body_integrals = self.molecule.two_body_integrals hc, hr1, hr2 = get_doci_from_integrals(one_body_integrals, two_body_integrals) n_qubits = one_body_integrals.shape[0] self.assertEqual(hc.shape, (n_qubits, )) self.assertEqual(hr1.shape, (n_qubits, n_qubits)) self.assertEqual(hr2.shape, (n_qubits, n_qubits)) for p in range(2): self.assertEqual( hc[p] + hr2[p, p], 2 * one_body_integrals[p, p] + two_body_integrals[p, p, p, p]) for q in range(2): if p != q: self.assertEqual(hr1[p, q], two_body_integrals[p, p, q, q]) self.assertEqual( hr2[p, q], 2 * two_body_integrals[p, q, q, p] - two_body_integrals[p, q, p, q])
class DOCIHamiltonianTest(unittest.TestCase): def setUp(self): self.geometry = [('H', (0., 0., 0.)), ('H', (0., 0., 0.7414))] self.basis = 'sto-3g' self.multiplicity = 1 self.filename = os.path.join(DATA_DIRECTORY, 'H2_sto-3g_singlet_0.7414') self.molecule = MolecularData(self.geometry, self.basis, self.multiplicity, filename=self.filename) self.molecule.load() def test_n_body_tensor_errors(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) with self.assertRaises(TypeError): doci_hamiltonian.n_body_tensors = 0 with self.assertRaises(IndexError): _ = doci_hamiltonian[((0, 0), (0, 0))] with self.assertRaises(IndexError): _ = doci_hamiltonian[((0, 0), (0, 0), (0, 0), (0, 0))] with self.assertRaises(IndexError): _ = doci_hamiltonian[((1, 1), (0, 0))] with self.assertRaises(IndexError): _ = doci_hamiltonian[((0, 1), (2, 1), (3, 0), (8, 0))] def test_errors_operations(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian2 = DOCIHamiltonian.zero(n_qubits=3) with self.assertRaises(TypeError): doci_hamiltonian += 'a' with self.assertRaises(TypeError): doci_hamiltonian -= 'a' with self.assertRaises(TypeError): doci_hamiltonian *= 'a' with self.assertRaises(TypeError): doci_hamiltonian /= 'a' with self.assertRaises(TypeError): doci_hamiltonian += doci_hamiltonian2 with self.assertRaises(TypeError): doci_hamiltonian -= doci_hamiltonian2 def test_adding_constants(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian += 2 self.assertAlmostEqual(doci_hamiltonian.constant, 2) doci_hamiltonian -= 3 self.assertAlmostEqual(doci_hamiltonian.constant, -1) def test_basic_operations(self): doci_hamiltonian1 = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian2 = DOCIHamiltonian.from_integrals( constant=self.molecule.nuclear_repulsion, one_body_integrals=self.molecule.one_body_integrals, two_body_integrals=self.molecule.two_body_integrals) self.assertTrue(doci_hamiltonian2 == doci_hamiltonian1 + doci_hamiltonian2) self.assertTrue(doci_hamiltonian1 - doci_hamiltonian2 == doci_hamiltonian2 / -1) self.assertTrue(doci_hamiltonian2 * 0 == doci_hamiltonian1) def test_error(self): doci_hamiltonian = DOCIHamiltonian.from_integrals( constant=self.molecule.nuclear_repulsion, one_body_integrals=self.molecule.one_body_integrals, two_body_integrals=self.molecule.two_body_integrals) with self.assertRaises(TypeError): doci_hamiltonian[((1, 0), (0, 1))] = 1 with self.assertRaises(IndexError): _ = doci_hamiltonian[((1, 0), )] with self.assertRaises(IndexError): _ = doci_hamiltonian[((1, 1), (0, 0))] with self.assertRaises(IndexError): _ = doci_hamiltonian[((0, 1), (1, 1), (0, 0), (2, 0))] def test_getting_setting_constant(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian.constant = 1 self.assertEqual(doci_hamiltonian[()], 1) def test_getting_setting_1body(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian.hc[0] = 2 doci_hamiltonian.hc[1] = 4 self.assertEqual(doci_hamiltonian[((0, 1), (0, 0))], 1) self.assertEqual(doci_hamiltonian[((1, 1), (1, 0))], 1) self.assertEqual(doci_hamiltonian[((2, 1), (2, 0))], 2) self.assertEqual(doci_hamiltonian[((3, 1), (3, 0))], 2) def test_getting_setting_hr2(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian.hr2[0, 0] = 2 doci_hamiltonian.hr2[1, 1] = 4 self.assertEqual(doci_hamiltonian[((0, 1), (1, 1), (1, 0), (0, 0))], 1) self.assertEqual(doci_hamiltonian[((1, 1), (0, 1), (0, 0), (1, 0))], 1) self.assertEqual(doci_hamiltonian[((2, 1), (3, 1), (3, 0), (2, 0))], 2) self.assertEqual(doci_hamiltonian[((3, 1), (2, 1), (2, 0), (3, 0))], 2) doci_hamiltonian.hr2[0, 1] = 2 self.assertEqual(doci_hamiltonian[((0, 1), (2, 1), (2, 0), (0, 0))], 1) self.assertEqual(doci_hamiltonian[((0, 1), (3, 1), (3, 0), (0, 0))], 1) self.assertEqual(doci_hamiltonian[((1, 1), (2, 1), (2, 0), (1, 0))], 1) self.assertEqual(doci_hamiltonian[((1, 1), (3, 1), (3, 0), (1, 0))], 1) def test_getting_setting_hr1(self): doci_hamiltonian = DOCIHamiltonian.zero(n_qubits=2) doci_hamiltonian.hr1[0, 1] = 2 self.assertEqual(doci_hamiltonian[(0, 1), (1, 1), (3, 0), (2, 0)], 1) self.assertEqual(doci_hamiltonian[(1, 1), (0, 1), (2, 0), (3, 0)], 1) def test_from_integrals_to_qubit(self): hamiltonian = jordan_wigner(self.molecule.get_molecular_hamiltonian()) doci_hamiltonian = DOCIHamiltonian.from_integrals( constant=self.molecule.nuclear_repulsion, one_body_integrals=self.molecule.one_body_integrals, two_body_integrals=self.molecule.two_body_integrals).qubit_operator hamiltonian_matrix = get_sparse_operator(hamiltonian).toarray() doci_hamiltonian_matrix = get_sparse_operator( doci_hamiltonian).toarray() diagonal = numpy.real(numpy.diag(hamiltonian_matrix)) doci_diagonal = numpy.real(numpy.diag(doci_hamiltonian_matrix)) position_of_doci_diag_in_h = [0] * len(doci_diagonal) for idx, doci_eigval in enumerate(doci_diagonal): closest_in_diagonal = None for idx2, eig in enumerate(diagonal): if closest_in_diagonal is None or abs(eig - doci_eigval) < abs( closest_in_diagonal - doci_eigval): closest_in_diagonal = eig position_of_doci_diag_in_h[idx] = idx2 assert abs(closest_in_diagonal - doci_eigval) < EQ_TOLERANCE, ( "Value " + str(doci_eigval) + " of the DOCI Hamiltonian " + "diagonal did not appear in the diagonal of the full " + "Hamiltonian. The closest value was " + str(closest_in_diagonal)) sub_matrix = hamiltonian_matrix[numpy.ix_(position_of_doci_diag_in_h, position_of_doci_diag_in_h)] assert numpy.allclose(doci_hamiltonian_matrix, sub_matrix), ( "The coupling between the DOCI states in the DOCI Hamiltonian " + "should be identical to that between these states in the full " + "Hamiltonian but the DOCI hamiltonian matrix\n" + str(doci_hamiltonian_matrix) + "\ndoes not match the corresponding sub-matrix of the full " + "Hamiltonian\n" + str(sub_matrix))
def make_atomic_lattice(nx_atoms, ny_atoms, nz_atoms, spacing, basis, atom_type='H', charge=0, filename=''): """Function to create atomic lattice with n_atoms. Args: nx_atoms: Integer, the length of lattice (in number of atoms). ny_atoms: Integer, the width of lattice (in number of atoms). nz_atoms: Integer, the depth of lattice (in number of atoms). spacing: The spacing between atoms in the lattice in Angstroms. basis: The basis in which to perform the calculation. atom_type: String, the atomic symbol of the element in the ring. this defaults to 'H' for Hydrogen. charge: An integer giving the total molecular charge. Defaults to 0. filename: An optional string to give a filename for the molecule. Returns: molecule: A an instance of the MolecularData class. Raises: MolecularLatticeError: If lattice specification is invalid. """ # Make geometry. geometry = [] for x_dimension in range(nx_atoms): for y_dimension in range(ny_atoms): for z_dimension in range(nz_atoms): x_coord = spacing * x_dimension y_coord = spacing * y_dimension z_coord = spacing * z_dimension geometry += [(atom_type, (x_coord, y_coord, z_coord))] # Set multiplicity. n_atoms = nx_atoms * ny_atoms * nz_atoms n_electrons = n_atoms * periodic_hash_table[atom_type] n_electrons -= charge if (n_electrons % 2): multiplicity = 2 else: multiplicity = 1 # Name molecule. dimensions = bool(nx_atoms > 1) + bool(ny_atoms > 1) + bool(nz_atoms > 1) if dimensions == 1: description = 'linear_{}'.format(spacing) elif dimensions == 2: description = 'planar_{}'.format(spacing) elif dimensions == 3: description = 'cubic_{}'.format(spacing) else: raise MolecularLatticeError('Invalid lattice dimensions.') # Create molecule and return. molecule = MolecularData(geometry, basis, multiplicity, charge, description, filename) return molecule