Exemplo n.º 1
0
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
    def setUp(self):
        # Set up molecule.
        geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))]
        basis = 'sto-3g'
        multiplicity = 1
        filename = os.path.join(THIS_DIRECTORY, 'data',
                                'H1-Li1_sto-3g_singlet_1.45')
        self.molecule = MolecularData(
            geometry, basis, multiplicity, filename=filename)
        self.molecule.load()

        # Get molecular Hamiltonian.
        self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian()

        self.hubbard_hamiltonian = fermi_hubbard(
            2, 2, 1.0, 4.0,
            chemical_potential=.2,
            magnetic_field=0.0,
            spinless=False)
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
class GetNumberPreservingSparseOperatorIntegrationTestLiH(unittest.TestCase):
    def setUp(self):
        # Set up molecule.
        geometry = [('Li', (0., 0., 0.)), ('H', (0., 0., 1.45))]
        basis = 'sto-3g'
        multiplicity = 1
        filename = os.path.join(THIS_DIRECTORY, 'data',
                                'H1-Li1_sto-3g_singlet_1.45')
        self.molecule = MolecularData(geometry,
                                      basis,
                                      multiplicity,
                                      filename=filename)
        self.molecule.load()

        # Get molecular Hamiltonian.
        self.molecular_hamiltonian = self.molecule.get_molecular_hamiltonian()

        self.hubbard_hamiltonian = fermi_hubbard(2,
                                                 2,
                                                 1.0,
                                                 4.0,
                                                 chemical_potential=.2,
                                                 magnetic_field=0.0,
                                                 spinless=False)

    def test_number_on_reference(self):
        sum_n_op = FermionOperator()
        sum_sparse_n_op = get_number_preserving_sparse_operator(
            sum_n_op,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False)

        space_size = sum_sparse_n_op.shape[0]
        reference = numpy.zeros((space_size))
        reference[0] = 1.0

        for i in range(self.molecule.n_qubits):
            n_op = FermionOperator(((i, 1), (i, 0)))
            sum_n_op += n_op

            sparse_n_op = get_number_preserving_sparse_operator(
                n_op,
                self.molecule.n_qubits,
                self.molecule.n_electrons,
                spin_preserving=False)

            sum_sparse_n_op += sparse_n_op

            expectation = reference.dot(sparse_n_op.dot(reference))

            if i < self.molecule.n_electrons:
                assert expectation == 1.0
            else:
                assert expectation == 0.0

        convert_after_adding = get_number_preserving_sparse_operator(
            sum_n_op,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False)

        assert scipy.sparse.linalg.norm(convert_after_adding -
                                        sum_sparse_n_op) < 1E-9

        assert reference.dot(sum_sparse_n_op.dot(reference)) - \
            self.molecule.n_electrons < 1E-9

    def test_space_size_correct(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        space_size = sparse_ham.shape[0]

        # Naive Hilbert space size is 2**12, or 4096.
        assert space_size == 225

    def test_hf_energy(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        space_size = sparse_ham.shape[0]
        reference = numpy.zeros((space_size))
        reference[0] = 1.0

        sparse_hf_energy = reference.dot(sparse_ham.dot(reference))

        assert numpy.linalg.norm(sparse_hf_energy -
                                 self.molecule.hf_energy) < 1E-9

    def test_one_body_hf_energy(self):
        one_body_part = self.molecular_hamiltonian
        one_body_part.two_body_tensor = numpy.zeros_like(
            one_body_part.two_body_tensor)

        one_body_fop = get_fermion_operator(one_body_part)
        one_body_regular_sparse_op = get_sparse_operator(one_body_fop)

        make_hf_fop = FermionOperator(((3, 1), (2, 1), (1, 1), (0, 1)))
        make_hf_sparse_op = get_sparse_operator(make_hf_fop, n_qubits=12)

        hf_state = numpy.zeros((2**12))
        hf_state[0] = 1.0
        hf_state = make_hf_sparse_op.dot(hf_state)

        regular_sparse_hf_energy = \
            (hf_state.dot(one_body_regular_sparse_op.dot(hf_state))).real

        one_body_sparse_op = get_number_preserving_sparse_operator(
            one_body_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        space_size = one_body_sparse_op.shape[0]
        reference = numpy.zeros((space_size))
        reference[0] = 1.0

        sparse_hf_energy = reference.dot(one_body_sparse_op.dot(reference))

        assert numpy.linalg.norm(sparse_hf_energy -
                                 regular_sparse_hf_energy) < 1E-9

    def test_ground_state_energy(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        eig_val, _ = scipy.sparse.linalg.eigsh(sparse_ham, k=1, which='SA')

        assert numpy.abs(eig_val[0] - self.molecule.fci_energy) < 1E-9

    def test_doubles_are_subset(self):
        reference_determinants = [[
            True, True, True, True, False, False, False, False, False, False,
            False, False
        ],
                                  [
                                      True, True, False, False, False, False,
                                      True, True, False, False, False, False
                                  ]]

        for reference_determinant in reference_determinants:
            reference_determinant = numpy.asarray(reference_determinant)
            doubles_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=2,
                                    spin_preserving=True)))
            doubles_int_state_array = doubles_state_array.dot(
                1 << numpy.arange(doubles_state_array.shape[1])[::-1])

            all_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=4,
                                    spin_preserving=True)))
            all_int_state_array = all_state_array.dot(
                1 << numpy.arange(all_state_array.shape[1])[::-1])

            for item in doubles_int_state_array:
                assert item in all_int_state_array

        for reference_determinant in reference_determinants:
            reference_determinant = numpy.asarray(reference_determinant)
            doubles_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=2,
                                    spin_preserving=True)))
            doubles_int_state_array = doubles_state_array.dot(
                1 << numpy.arange(doubles_state_array.shape[1])[::-1])

            all_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=4,
                                    spin_preserving=False)))
            all_int_state_array = all_state_array.dot(
                1 << numpy.arange(all_state_array.shape[1])[::-1])

            for item in doubles_int_state_array:
                assert item in all_int_state_array

        for reference_determinant in reference_determinants:
            reference_determinant = numpy.asarray(reference_determinant)
            doubles_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=2,
                                    spin_preserving=False)))
            doubles_int_state_array = doubles_state_array.dot(
                1 << numpy.arange(doubles_state_array.shape[1])[::-1])

            all_state_array = numpy.asarray(
                list(
                    _iterate_basis_(reference_determinant,
                                    excitation_level=4,
                                    spin_preserving=False)))
            all_int_state_array = all_state_array.dot(
                1 << numpy.arange(all_state_array.shape[1])[::-1])

            for item in doubles_int_state_array:
                assert item in all_int_state_array

    def test_full_ham_hermitian(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        assert scipy.sparse.linalg.norm(sparse_ham - sparse_ham.getH()) < 1E-9

    def test_full_ham_hermitian_non_spin_preserving(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False)

        assert scipy.sparse.linalg.norm(sparse_ham - sparse_ham.getH()) < 1E-9

    def test_singles_simple_one_body_term_hermitian(self):
        fop = FermionOperator(((3, 1), (1, 0)))
        fop_conj = FermionOperator(((1, 1), (3, 0)))

        sparse_op = get_number_preserving_sparse_operator(
            fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        sparse_op_conj = get_number_preserving_sparse_operator(
            fop_conj,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        assert scipy.sparse.linalg.norm(sparse_op -
                                        sparse_op_conj.getH()) < 1E-9

    def test_singles_simple_two_body_term_hermitian(self):
        fop = FermionOperator(((3, 1), (8, 1), (1, 0), (4, 0)))
        fop_conj = FermionOperator(((4, 1), (1, 1), (8, 0), (3, 0)))

        sparse_op = get_number_preserving_sparse_operator(
            fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        sparse_op_conj = get_number_preserving_sparse_operator(
            fop_conj,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        assert scipy.sparse.linalg.norm(sparse_op -
                                        sparse_op_conj.getH()) < 1E-9

    def test_singles_repeating_two_body_term_hermitian(self):
        fop = FermionOperator(((3, 1), (1, 1), (5, 0), (1, 0)))
        fop_conj = FermionOperator(((5, 1), (1, 1), (3, 0), (1, 0)))

        sparse_op = get_number_preserving_sparse_operator(
            fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        sparse_op_conj = get_number_preserving_sparse_operator(
            fop_conj,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        assert scipy.sparse.linalg.norm(sparse_op -
                                        sparse_op_conj.getH()) < 1E-9

    def test_singles_ham_hermitian(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=1)

        assert scipy.sparse.linalg.norm(sparse_ham - sparse_ham.getH()) < 1E-9

    def test_singles_ham_hermitian_non_spin_preserving(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False,
            excitation_level=1)

        assert scipy.sparse.linalg.norm(sparse_ham - sparse_ham.getH()) < 1E-9

    def test_cisd_energy(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True,
            excitation_level=2)

        eig_val, _ = scipy.sparse.linalg.eigsh(sparse_ham, k=1, which='SA')

        assert numpy.abs(eig_val[0] - self.molecule.cisd_energy) < 1E-9

    def test_cisd_energy_non_spin_preserving(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False,
            excitation_level=2)

        eig_val, _ = scipy.sparse.linalg.eigsh(sparse_ham, k=1, which='SA')

        assert numpy.abs(eig_val[0] - self.molecule.cisd_energy) < 1E-9

    def test_cisd_matches_fci_energy_two_electron_hubbard(self):
        hamiltonian_fop = self.hubbard_hamiltonian

        sparse_ham_cisd = get_number_preserving_sparse_operator(
            hamiltonian_fop, 8, 2, spin_preserving=True, excitation_level=2)

        sparse_ham_fci = get_sparse_operator(hamiltonian_fop, n_qubits=8)

        eig_val_cisd, _ = scipy.sparse.linalg.eigsh(sparse_ham_cisd,
                                                    k=1,
                                                    which='SA')
        eig_val_fci, _ = scipy.sparse.linalg.eigsh(sparse_ham_fci,
                                                   k=1,
                                                   which='SA')

        assert numpy.abs(eig_val_cisd[0] - eig_val_fci[0]) < 1E-9

    def test_weird_determinant_matches_fci_energy_two_electron_hubbard(self):
        hamiltonian_fop = self.hubbard_hamiltonian

        sparse_ham_cisd = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            8,
            2,
            spin_preserving=True,
            excitation_level=2,
            reference_determinant=numpy.asarray(
                [False, False, True, True, False, False, False, False]))

        sparse_ham_fci = get_sparse_operator(hamiltonian_fop, n_qubits=8)

        eig_val_cisd, _ = scipy.sparse.linalg.eigsh(sparse_ham_cisd,
                                                    k=1,
                                                    which='SA')
        eig_val_fci, _ = scipy.sparse.linalg.eigsh(sparse_ham_fci,
                                                   k=1,
                                                   which='SA')

        assert numpy.abs(eig_val_cisd[0] - eig_val_fci[0]) < 1E-9

    def test_number_restricted_spectra_match_molecule(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham_number_preserving = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=False)

        sparse_ham = get_sparse_operator(hamiltonian_fop,
                                         self.molecule.n_qubits)

        sparse_ham_restricted_number_preserving = jw_number_restrict_operator(
            sparse_ham,
            n_electrons=self.molecule.n_electrons,
            n_qubits=self.molecule.n_qubits)

        spectrum_from_new_sparse_method = sparse_eigenspectrum(
            sparse_ham_number_preserving)

        spectrum_from_old_sparse_method = sparse_eigenspectrum(
            sparse_ham_restricted_number_preserving)

        spectral_deviation = numpy.amax(
            numpy.absolute(spectrum_from_new_sparse_method -
                           spectrum_from_old_sparse_method))
        self.assertAlmostEqual(spectral_deviation, 0.)

    def test_number_restricted_spectra_match_hubbard(self):
        hamiltonian_fop = self.hubbard_hamiltonian

        sparse_ham_number_preserving = get_number_preserving_sparse_operator(
            hamiltonian_fop, 8, 4, spin_preserving=False)

        sparse_ham = get_sparse_operator(hamiltonian_fop, 8)

        sparse_ham_restricted_number_preserving = jw_number_restrict_operator(
            sparse_ham, n_electrons=4, n_qubits=8)

        spectrum_from_new_sparse_method = sparse_eigenspectrum(
            sparse_ham_number_preserving)

        spectrum_from_old_sparse_method = sparse_eigenspectrum(
            sparse_ham_restricted_number_preserving)

        spectral_deviation = numpy.amax(
            numpy.absolute(spectrum_from_new_sparse_method -
                           spectrum_from_old_sparse_method))
        self.assertAlmostEqual(spectral_deviation, 0.)

    def test_number_sz_restricted_spectra_match_molecule(self):
        hamiltonian_fop = get_fermion_operator(self.molecular_hamiltonian)

        sparse_ham_number_sz_preserving = get_number_preserving_sparse_operator(
            hamiltonian_fop,
            self.molecule.n_qubits,
            self.molecule.n_electrons,
            spin_preserving=True)

        sparse_ham = get_sparse_operator(hamiltonian_fop,
                                         self.molecule.n_qubits)

        sparse_ham_restricted_number_sz_preserving = jw_sz_restrict_operator(
            sparse_ham,
            0,
            n_electrons=self.molecule.n_electrons,
            n_qubits=self.molecule.n_qubits)

        spectrum_from_new_sparse_method = sparse_eigenspectrum(
            sparse_ham_number_sz_preserving)

        spectrum_from_old_sparse_method = sparse_eigenspectrum(
            sparse_ham_restricted_number_sz_preserving)

        spectral_deviation = numpy.amax(
            numpy.absolute(spectrum_from_new_sparse_method -
                           spectrum_from_old_sparse_method))
        self.assertAlmostEqual(spectral_deviation, 0.)

    def test_number_sz_restricted_spectra_match_hubbard(self):
        hamiltonian_fop = self.hubbard_hamiltonian

        sparse_ham_number_sz_preserving = get_number_preserving_sparse_operator(
            hamiltonian_fop, 8, 4, spin_preserving=True)

        sparse_ham = get_sparse_operator(hamiltonian_fop, 8)

        sparse_ham_restricted_number_sz_preserving = jw_sz_restrict_operator(
            sparse_ham, 0, n_electrons=4, n_qubits=8)

        spectrum_from_new_sparse_method = sparse_eigenspectrum(
            sparse_ham_number_sz_preserving)

        spectrum_from_old_sparse_method = sparse_eigenspectrum(
            sparse_ham_restricted_number_sz_preserving)

        spectral_deviation = numpy.amax(
            numpy.absolute(spectrum_from_new_sparse_method -
                           spectrum_from_old_sparse_method))
        self.assertAlmostEqual(spectral_deviation, 0.)