Ejemplo n.º 1
0
    def slice_to_two(self, subscripts, out=None, factor=1.0, clear=True):
        """Returns a two-index contraction of the four-index object.

           **Arguments:**

           subscripts
                Any of ``aabb->ab``, ``abab->ab``, ``abba->ab``

           **Optional arguments:**

           out, factor, clear
                See :py:meth:`DenseLinalgFactory.einsum`
        """
        # Error checking
        check_options('subscripts', subscripts, 'aabb->ab', 'abab->ab', 'abba->ab')
        # Handle output argument
        if out is None:
            out = DenseTwoIndex(self.nbasis)
        else:
            check_type('out', out, DenseTwoIndex)
            if clear:
                out.clear()
        # Actual computation
        if subscripts == 'aabb->ab':
            out._array[:] += factor*np.einsum('xab,xab->ab', self._array, self._array2)
        elif subscripts == 'abab->ab':
            out._array[:] += factor*np.einsum('xaa,xbb->ab', self._array, self._array2)
        elif subscripts == 'abba->ab':
            out._array[:] += factor*np.einsum('xab,xba->ab', self._array, self._array2)
        return out
Ejemplo n.º 2
0
    def slice_to_three(self, subscripts, out=None, factor=1.0, clear=True):
        """Returns a three-index contraction of the four-index object.

           **Arguments:**

           subscripts
                Any of ``abcc->bac``, ``abcc->abc``, ``abcb->abc``, ``abbc->abc``

           **Optional arguments:**

           out, factor, clear
                See :py:meth:`DenseLinalgFactory.einsum`
        """
        # Error checking
        check_options('subscripts', subscripts, 'abcc->bac', 'abcc->abc', 'abcb->abc', 'abbc->abc')
        if out is None:
            out = DenseThreeIndex(self.nbasis)
        else:
            check_type('out', out, DenseThreeIndex)
            if clear:
                out.clear()
        # Actual computation
        if subscripts == 'abbc->abc':
            slice_to_three_abbc_abc(self._array, self._array2, out._array, factor, clear)
        elif subscripts == 'abcc->bac':
            slice_to_three_abcc_bac(self._array, self._array2, out._array, factor, clear)
        elif subscripts == 'abcc->abc':
            slice_to_three_abcc_abc(self._array, self._array2, out._array, factor, clear)
        elif subscripts == 'abcb->abc':
            L_r = np.diagonal(self._array2, axis1=1, axis2=2)
            out._array[:] += factor*np.tensordot(self._array, L_r, [(0,),(0,)]).swapaxes(1,2)
        return out
Ejemplo n.º 3
0
    def init_two_dm(self, select):
        r'''Initialize 2-RDM as TwoIndex object

           Only the symmetry-unique elements of the (response) 2-RDM are
           stored. These are matrix elements of type

           .. math::

                Gamma_{p\bar{q}p\bar{q}}

           (spin-up and spin-down (bar-sign)) or

           .. math::
                Gamma_{p\bar{p}q\bar{q}}

           and are stored as elements :math:`{pq}` of two_dm_pqpq, and
           two_dm_ppqq.

           **Arguments**

           select
                '(r(esponse))ppqq', or '(r(esponse))pqpq'.
        '''
        check_options('twodm', select, 'ppqq', 'pqpq', 'rppqq', 'rpqpq')
        dm, new = self._cache.load('two_dm_%s' % select,
                                   alloc=(self._lf.create_two_index,
                                          self.nbasis),
                                   tags='d')
        if not new:
            raise RuntimeError(
                'The density matrix two_dm_%s already exists. Call two_dm_%s.clear prior to updating the 2DM.'
                % select)
        return dm
Ejemplo n.º 4
0
    def contract_two_to_four(self, subscripts, two, out=None, factor=1.0, clear=True):
        '''Contracts with a two-index object to obtain a four-index object.

           **Arguments:**

           subscripts
                Any of ``abcd,cd->acbd``, ``abcd,cd->acdb``, ``abcd,cb->acdb``,
                ``abcd,cb->acbd``, ``abcd,ab->acbd``, ``abcd,ab->acdb``,
                ``abcd,ad->acbd``, ``abcd,ad->acdb``, ``abcd,ad->abcd``,
                ``abcd,ad->abdc``, ``abcd,bd->abcd``, ``abcd,bd->abdc``,
                ``abcd,bc->abdc``, ``abcd,bc->abcd``, ``abcd,ac->abcd``,
                ``abcd,ac->abdc``

           two
                An instance of DenseTwoIndex.

           **Optional arguments:**

           out, factor, clear
                See :py:meth:`DenseLinalgFactory.einsum`
        '''
        check_options('subscripts', subscripts, 'abcd,cd->acbd',
            'abcd,cd->acdb', 'abcd,cb->acdb', 'abcd,cb->acbd', 'abcd,ab->acbd',
            'abcd,ab->acdb', 'abcd,ad->acbd', 'abcd,ad->acdb', 'abcd,ad->abcd',
            'abcd,ad->abdc', 'abcd,bd->abcd', 'abcd,bd->abdc', 'abcd,bc->abdc',
            'abcd,bc->abcd', 'abcd,ac->abcd', 'abcd,ac->abdc')
        raise NotImplementedError
Ejemplo n.º 5
0
    def init_two_dm(self, select):
        r'''Initialize 2-RDM as TwoIndex object

           Only the symmetry-unique elements of the (response) 2-RDM are
           stored. These are matrix elements of type

           .. math::

                Gamma_{p\bar{q}p\bar{q}}

           (spin-up and spin-down (bar-sign)) or

           .. math::
                Gamma_{p\bar{p}q\bar{q}}

           and are stored as elements :math:`{pq}` of two_dm_pqpq, and
           two_dm_ppqq.

           **Arguments**

           select
                '(r(esponse))ppqq', or '(r(esponse))pqpq'.
        '''
        check_options('twodm', select, 'ppqq', 'pqpq', 'rppqq', 'rpqpq')
        dm, new = self._cache.load('two_dm_%s' % select, alloc=(self._lf.create_two_index, self.nbasis), tags='d')
        if not new:
            raise RuntimeError('The density matrix two_dm_%s already exists. Call two_dm_%s.clear prior to updating the 2DM.' % select)
        return dm
Ejemplo n.º 6
0
    def contract_two_to_two(self, subscripts, two, out=None, factor=1.0, clear=True):
        """Contract self with a two-index to obtain a two-index.

           **Arguments:**

           subscripts
                Any of ``abcd,bd->ac`` (direct), ``abcd,cb->ad`` (exchange)

           two
                The input two-index object. (DenseTwoIndex)

           **Optional arguments:**

           out, factor, clear
                See :py:meth:`DenseLinalgFactory.einsum`
        """
        check_options('subscripts', subscripts, 'abcd,bd->ac', 'abcd,cb->ad')
        if out is None:
            out = DenseTwoIndex(self.nbasis)
            if clear:
                out.clear()
        else:
            check_type('out', out, DenseTwoIndex)
        if subscripts == 'abcd,bd->ac':
            tmp = np.tensordot(self._array2, two._array, axes=([(1,2),(1,0)]))
            out._array[:] += factor*np.tensordot(self._array, tmp, [0,0])
        elif subscripts == 'abcd,cb->ad':
            tmp = np.tensordot(self._array2, two._array, axes=([1,1]))
            out._array[:] += factor*np.tensordot(self._array, tmp, ([0,2],[0,2]))
        return out
Ejemplo n.º 7
0
 def assign_locblock(self):
     '''Get localization block. A OneIndex instance'''
     check_options('block', self.locblock, 'occ', 'virt')
     block = self.lf.create_one_index()
     if self.locblock == 'occ':
         block.assign(1.0, end0=self.nocc)
     elif self.locblock == 'virt':
         block.assign(1.0, begin0=self.nocc)
     return block
Ejemplo n.º 8
0
 def assign_locblock(self):
     '''Get localization block. A OneIndex instance'''
     check_options('block', self.locblock, 'occ', 'virt')
     block = self.lf.create_one_index()
     if self.locblock=='occ':
         block.assign(1.0, end0=self.nocc)
     elif self.locblock=='virt':
         block.assign(1.0, begin0=self.nocc)
     return block
Ejemplo n.º 9
0
 def symmetrize(self, symmetry=8):
     check_options('symmetry', symmetry, 1, 2, 4, 8)
     if symmetry in (2, 8) and self.is_decoupled:
         # This is a different type of symmetrization than in the dense case!
         self._array[:] += self._array2
         self._array *= 0.5
         self.reset_array2()
     if symmetry in (4, 8):
         self._array[:] = self._array + self._array.transpose(0,2,1)
         if self.is_decoupled:
             self._array2[:] = self._array2 + self._array2.transpose(0,2,1)
Ejemplo n.º 10
0
    def init_one_dm(self, select):
        '''Initialize 1-RDM as OneIndex object

           The 1-RDM expressed in the natural orbital basis is diagonal and
           only the diagonal elements are stored.

           **Arguments**

           select
                'ps2' or 'response'.
        '''
        check_options('onedm', select, 'ps2', 'response')
        dm, new = self._cache.load('one_dm_%s' % select, alloc=(self._lf.create_one_index, self.nbasis), tags='d')
        if not new:
            raise RuntimeError('The density matrix one_dm_%s already exists. Call one_dm_%s.clear prior to updating the 1DM.' % select)
        return dm
Ejemplo n.º 11
0
    def compute_single_orbital_entropy(self, select='vonNeumann'):
        '''Compute single-orbital entropy for each orbital in the active space.
           Currently, only the von Neumann entropy is supported.

           The 1-ODM is assumed to be diagonalized.

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        for index in range(self.nbasis):
            self.compute_odm1(index)
        for item in self.odm1:
            mat = item[1]
            term = 0.0
            for ind in range(mat.shape[0]):
                term -= self.calculate_entropy_term(mat.get_element(ind), select)
            self.so_entropy.set_element(item[0], term)
Ejemplo n.º 12
0
    def compute_single_orbital_entropy(self, select='vonNeumann'):
        '''Compute single-orbital entropy for each orbital in the active space.
           Currently, only the von Neumann entropy is supported.

           The 1-ODM is assumed to be diagonalized.

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        for index in range(self.nbasis):
            self.compute_odm1(index)
        for item in self.odm1:
            mat = item[1]
            term = 0.0
            for ind in range(mat.shape[0]):
                term -= self.calculate_entropy_term(mat.get_element(ind),
                                                    select)
            self.so_entropy.set_element(item[0], term)
Ejemplo n.º 13
0
    def init_one_dm(self, select):
        '''Initialize 1-RDM as OneIndex object

           The 1-RDM expressed in the natural orbital basis is diagonal and
           only the diagonal elements are stored.

           **Arguments**

           select
                'ps2' or 'response'.
        '''
        check_options('onedm', select, 'ps2', 'response')
        dm, new = self._cache.load('one_dm_%s' % select,
                                   alloc=(self._lf.create_one_index,
                                          self.nbasis),
                                   tags='d')
        if not new:
            raise RuntimeError(
                'The density matrix one_dm_%s already exists. Call one_dm_%s.clear prior to updating the 1DM.'
                % select)
        return dm
Ejemplo n.º 14
0
    def calculate_entropy_term(self, val, select='vonNeumann'):
        '''Calculate entropic term

           **Arguements**

           val
                Used to determine entropy

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        if select=='vonNeumann':
            if val > 0.0:
                return np.log(val)*val
            else:
                if abs(val) > 1e-6:
                    log('Neglecting negative value %f in entropy function' % val)
                return 0.0
Ejemplo n.º 15
0
    def calculate_entropy_term(self, val, select='vonNeumann'):
        '''Calculate entropic term

           **Arguements**

           val
                Used to determine entropy

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        if select == 'vonNeumann':
            if val > 0.0:
                return np.log(val) * val
            else:
                if abs(val) > 1e-6:
                    log('Neglecting negative value %f in entropy function' %
                        val)
                return 0.0
Ejemplo n.º 16
0
    def compute_two_orbital_entropy(self, select='vonNeumann'):
        '''Compute two-orbital entropy for each orbital in the active space.
           Currently, only the von Neumann entropy is supported.

           The 1-ODM and 2-ODM are assumed to be diagonalized.

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        for index1 in range(self.nbasis):
            for index2 in range(self.nbasis):
                if index2 is not index1:
                    self.compute_odm2(index1, index2)
        for item in self.odm2:
            mat = item[2]
            term = 0.0
            for ind in range(mat.shape[0]):
                term -= self.calculate_entropy_term(mat.get_element(ind), select)
            self.to_entropy.set_element(item[0], item[1], term)
Ejemplo n.º 17
0
    def generate_guess(self, guess, dim=None):
        '''Generate a guess of type 'guess'.

           **Arguments:**

           guess
               A dictionary, containing the type of guess.

           **Optional arguments:**

           dim
               Length of guess.
        '''
        check_options('guess.type', guess['type'], 'random', 'const')
        check_type('guess.factor', guess['factor'], int, float)
        if guess['factor'] == 0:
            raise ValueError('Scaling factor must be different from 0.')
        if dim is None:
            dim = self.dimension
        if guess['type'] == 'random':
            return np.random.random(dim) * guess['factor']
        elif guess['type'] == 'const':
            return np.ones(dim) * guess['factor']
Ejemplo n.º 18
0
    def generate_guess(self, guess, dim=None):
        '''Generate a guess of type 'guess'.

           **Arguments:**

           guess
               A dictionary, containing the type of guess.

           **Optional arguments:**

           dim
               Length of guess.
        '''
        check_options('guess.type', guess['type'], 'random', 'const')
        check_type('guess.factor', guess['factor'], int, float)
        if guess['factor'] == 0:
            raise ValueError('Scaling factor must be different from 0.')
        if dim is None:
            dim = self.dimension
        if guess['type'] == 'random':
            return np.random.random(dim)*guess['factor']
        elif guess['type'] == 'const':
            return np.ones(dim)*guess['factor']
Ejemplo n.º 19
0
    def compute_two_orbital_entropy(self, select='vonNeumann'):
        '''Compute two-orbital entropy for each orbital in the active space.
           Currently, only the von Neumann entropy is supported.

           The 1-ODM and 2-ODM are assumed to be diagonalized.

           **Optional arguments:**

           select
                Select entropy function. Default: von Neumann.
        '''
        check_options('select', select, 'vonNeumann')
        for index1 in range(self.nbasis):
            for index2 in range(self.nbasis):
                if index2 is not index1:
                    self.compute_odm2(index1, index2)
        for item in self.odm2:
            mat = item[2]
            term = 0.0
            for ind in range(mat.shape[0]):
                term -= self.calculate_entropy_term(mat.get_element(ind),
                                                    select)
            self.to_entropy.set_element(item[0], item[1], term)
Ejemplo n.º 20
0
    def __init__(self, lf, **kw):
        """
           **Arguments:**

           lf
                A LinalgFactory instance

           **Keywords:**
                :method: step search method used, one of ``trust-region``
                         (default), ``None``, ``backtracking``
                :alpha: scaling factor for step, used in ``backtracking`` and
                        ``None`` method (default 0.75)
                :c1: parameter used in ``backtracking`` (default 1e-4)
                :minalpha: minimum step length used in ``backracking``
                           (default 1e-6)
                :maxiterouter: maximum number of step search steps (default 10)
                :maxiterinner: maximum number of optimization steps in each
                               step search step (used only in pcg, default 500)
                :maxeta: upper bound for estimated vs actual change in
                         ``trust-region`` (default 0.75)
                :mineta: lower bound for estimated vs actual change in
                         ``trust-region`` (default 0.25)
                :upscale: scaling factor to increase trust radius in
                          ``trust-region`` (default 2.0)
                :downscale: scaling factor to decrease trust radius in
                            ``trust-region`` and step length in ``backtracking``
                            (float) (default 0.25)
                :trustradius: initial trust radius (default 0.75)
                :maxtrustradius: maximum trust radius (default 0.75)
                :threshold: trust-region optimization threshold, only used in
                            ``pcg`` method of ``trust-region``
                :optimizer: optimizes step to boundary of trust radius. One of
                            ``pcg``, ``dogleg``, ``ddl`` (default ddl)
        """
        self.lf = lf
        #
        # Check keywords and set default arguments, types and options are also
        # checked
        #
        names = []
        def _helper(x,y):
            names.append(x)
            kw.setdefault(x,y)
        _helper('method', 'trust-region')
        _helper('alpha', 1.0)
        _helper('c1', 0.0001)
        _helper('minalpha', 1e-6)
        _helper('maxiterouter', 10)
        _helper('maxiterinner', 500)
        _helper('maxeta', 0.75)
        _helper('mineta', 0.25)
        _helper('upscale', 2.0)
        _helper('downscale', 0.25)
        _helper('trustradius', 0.75)
        _helper('maxtrustradius', 0.75)
        _helper('threshold', 1e-8)
        _helper('optimizer', 'ddl')

        for name, value in kw.items():
            if name not in names:
                raise ValueError("Unknown keyword argument %s" % name)
            if value is not None:
                if value < 0:
                    raise ValueError('Cannot set attribute %s because of illegal value %s' %(name, value))
                setattr(self, name, kw[name])

        check_options('method', self.method, 'None', 'backtracking', 'trust-region')
        check_options('optimizer', self.optimizer, 'pcg', 'dogleg', 'ddl')
        check_type('alpha', self.alpha, int, float)
        check_type('c1', self.c1, int, float)
        check_type('minalpha', self.minalpha, int, float)
        check_type('maxiterouter', self.maxiterouter, int)
        check_type('maxiterinner', self.maxiterinner, int)
        check_type('maxeta', self.maxeta, int, float)
        check_type('mineta', self.mineta, int, float)
        check_type('upscale', self.upscale, float)
        check_type('downscale', self.downscale, float)
        check_type('trustradius', self.trustradius, float)
        check_type('maxtrustradius', self.maxtrustradius, float)
        check_type('threshold', self.threshold, float)

        self.alpha0 = self.alpha

        def _get_lf(self):
            return self.lf

        lf = property(_get_lf)

        def _get_method(self):
            return kw.pop('method')

        method = property(_get_method)

        def _get_maxeta(self):
            return kw.pop('maxeta')

        maxeta = property(_get_maxeta)

        def _get_mineta(self):
            return kw.pop('mineta')

        mineta = property(_get_mineta)

        def _get_upscale(self):
            return kw.pop('upscale')

        upscale = property(_get_upscale)

        def _get_downscale(self):
            return kw.pop('downscale')

        downscale = property(_get_downscale)

        def _get_maxiterouter(self):
            return kw.pop('maxiterouter')

        maxiterouter = property(_get_maxiterouter)

        def _get_maxiterinner(self):
            return kw.pop('maxiterinner')

        maxiterinner = property(_get_maxiterinner)

        def _get_alpha(self):
            return kw.pop('alpha')

        alpha = property(_get_alpha)

        def _get_minalpha(self):
            return kw.pop('minalpha')

        minalpha = property(_get_minalpha)

        def _get_c1(self):
            return kw.pop('c1')

        c1 = property(_get_c1)

        def _get_maxtrustradius(self):
            return kw.pop('maxtrustradius')

        maxtrustradius = property(_get_maxtrustradius)

        def _get_trustradius(self):
            return kw.pop('trustradius')

        trustradius = property(_get_trustradius)

        def _get_threshold(self):
            return kw.pop('threshold')

        threshold = property(_get_threshold)

        def _get_optimizer(self):
            return kw.pop('optimizer')

        optimizer = property(_get_optimizer)
Ejemplo n.º 21
0
def split_core_active(one, two, ecore, orb, ncore, nactive, indextrans='tensordot'):
    '''Reduce a Hamiltonian to an active space

       Works only for restricted wavefunctions.

       **Arguments:**

       one/two
            One and two-electron integrals.

       ecore
            The core energy of the given Hamiltonian. In the case of a standard
            molecular system, this is the nuclear nuclear repulsion.

       orb
            The MO expansion coefficients. An Expansion instance. If None,
            integrals are assued to be already transformed into the mo basis
            and no transformation is carried out in this function.

       ncore
            The number of frozen core orbitals (int)

       nactive
            The number of active orbitals (int)

       **Optional arguments:**

       indextrans
            4-index transformation (str). One of ``tensordot``, ``einsum``

       **Returns** a tuple with three values:

       one_small
            The one-body operator in the small space

       two_small
            The two-body operator in the small space

       ecore
            The core energy, i.e. the sum of the given core energy and HF
            contributions from the core orbitals.
    '''
    #
    # Check type/option of arguments
    #
    check_type('ncore', ncore, int)
    check_type('nactive', nactive, int)
    check_options('indextrans', indextrans, 'tensordot', 'einsum')
    if ncore <= 0 or nactive <= 0:
        raise ValueError('ncore and nactive must be strictly positive.')
    if nactive+ncore > one.nbasis:
        raise ValueError('More active orbitals than basis functions.')

    #
    # Optional transformation to mo basis
    #
    if orb is None:
        one_mo = one
        two_mo = two
    else:
        # No need to check orb. This is done in transform_integrals function
        (one_mo,), (two_mo,) = transform_integrals(one, two, indextrans, orb)

    # Core energy
    norb = one.nbasis
    #   One body term
    ecore += 2*one_mo.trace(0, ncore, 0, ncore)
    #   Direct part
    ecore += two_mo.slice_to_two('abab->ab', None, 2.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum()
    #   Exchange part
    ecore += two_mo.slice_to_two('abba->ab', None,-1.0, True, 0, ncore, 0, ncore, 0, ncore, 0, ncore).sum()

    # Active space one-body integrals
    one_mo_corr = one_mo.new()
    #   Direct part
    two_mo.contract_to_two('abcb->ac', one_mo_corr, 2.0, True, 0, norb, 0, ncore, 0, norb, 0, ncore)
    #   Exchange part
    two_mo.contract_to_two('abbc->ac', one_mo_corr,-1.0, False, 0, norb, 0, ncore, 0, ncore, 0, norb)
    one_mo.iadd(one_mo_corr, 1.0)
    #one_mo.iadd_t(one_mo_corr, 1.0)

    #
    # Store in smaller n-index objects
    #
    one_mo_small = one_mo.copy(ncore, ncore+nactive, ncore, ncore+nactive)
    two_mo_small = two_mo.copy(ncore, ncore+nactive, ncore, ncore+nactive,
                               ncore, ncore+nactive, ncore, ncore+nactive)

    # Done
    return one_mo_small, two_mo_small, ecore
Ejemplo n.º 22
0
    def __init__(self, lf, **kw):
        """
           **Arguments:**

           lf
                A LinalgFactory instance

           **Keywords:**
                :method: step search method used, one of ``trust-region``
                         (default), ``None``, ``backtracking``
                :alpha: scaling factor for step, used in ``backtracking`` and
                        ``None`` method (default 0.75)
                :c1: parameter used in ``backtracking`` (default 1e-4)
                :minalpha: minimum step length used in ``backracking``
                           (default 1e-6)
                :maxiterouter: maximum number of step search steps (default 10)
                :maxiterinner: maximum number of optimization steps in each
                               step search step (used only in pcg, default 500)
                :maxeta: upper bound for estimated vs actual change in
                         ``trust-region`` (default 0.75)
                :mineta: lower bound for estimated vs actual change in
                         ``trust-region`` (default 0.25)
                :upscale: scaling factor to increase trust radius in
                          ``trust-region`` (default 2.0)
                :downscale: scaling factor to decrease trust radius in
                            ``trust-region`` and step length in ``backtracking``
                            (float) (default 0.25)
                :trustradius: initial trust radius (default 0.75)
                :maxtrustradius: maximum trust radius (default 0.75)
                :threshold: trust-region optimization threshold, only used in
                            ``pcg`` method of ``trust-region``
                :optimizer: optimizes step to boundary of trust radius. One of
                            ``pcg``, ``dogleg``, ``ddl`` (default ddl)
        """
        self.lf = lf
        #
        # Check keywords and set default arguments, types and options are also
        # checked
        #
        names = []

        def _helper(x, y):
            names.append(x)
            kw.setdefault(x, y)

        _helper('method', 'trust-region')
        _helper('alpha', 1.0)
        _helper('c1', 0.0001)
        _helper('minalpha', 1e-6)
        _helper('maxiterouter', 10)
        _helper('maxiterinner', 500)
        _helper('maxeta', 0.75)
        _helper('mineta', 0.25)
        _helper('upscale', 2.0)
        _helper('downscale', 0.25)
        _helper('trustradius', 0.75)
        _helper('maxtrustradius', 0.75)
        _helper('threshold', 1e-8)
        _helper('optimizer', 'ddl')

        for name, value in kw.items():
            if name not in names:
                raise ValueError("Unknown keyword argument %s" % name)
            if value is not None:
                if value < 0:
                    raise ValueError(
                        'Cannot set attribute %s because of illegal value %s' %
                        (name, value))
                setattr(self, name, kw[name])

        check_options('method', self.method, 'None', 'backtracking',
                      'trust-region')
        check_options('optimizer', self.optimizer, 'pcg', 'dogleg', 'ddl')
        check_type('alpha', self.alpha, int, float)
        check_type('c1', self.c1, int, float)
        check_type('minalpha', self.minalpha, int, float)
        check_type('maxiterouter', self.maxiterouter, int)
        check_type('maxiterinner', self.maxiterinner, int)
        check_type('maxeta', self.maxeta, int, float)
        check_type('mineta', self.mineta, int, float)
        check_type('upscale', self.upscale, float)
        check_type('downscale', self.downscale, float)
        check_type('trustradius', self.trustradius, float)
        check_type('maxtrustradius', self.maxtrustradius, float)
        check_type('threshold', self.threshold, float)

        self.alpha0 = self.alpha

        def _get_lf(self):
            return self.lf

        lf = property(_get_lf)

        def _get_method(self):
            return kw.pop('method')

        method = property(_get_method)

        def _get_maxeta(self):
            return kw.pop('maxeta')

        maxeta = property(_get_maxeta)

        def _get_mineta(self):
            return kw.pop('mineta')

        mineta = property(_get_mineta)

        def _get_upscale(self):
            return kw.pop('upscale')

        upscale = property(_get_upscale)

        def _get_downscale(self):
            return kw.pop('downscale')

        downscale = property(_get_downscale)

        def _get_maxiterouter(self):
            return kw.pop('maxiterouter')

        maxiterouter = property(_get_maxiterouter)

        def _get_maxiterinner(self):
            return kw.pop('maxiterinner')

        maxiterinner = property(_get_maxiterinner)

        def _get_alpha(self):
            return kw.pop('alpha')

        alpha = property(_get_alpha)

        def _get_minalpha(self):
            return kw.pop('minalpha')

        minalpha = property(_get_minalpha)

        def _get_c1(self):
            return kw.pop('c1')

        c1 = property(_get_c1)

        def _get_maxtrustradius(self):
            return kw.pop('maxtrustradius')

        maxtrustradius = property(_get_maxtrustradius)

        def _get_trustradius(self):
            return kw.pop('trustradius')

        trustradius = property(_get_trustradius)

        def _get_threshold(self):
            return kw.pop('threshold')

        threshold = property(_get_threshold)

        def _get_optimizer(self):
            return kw.pop('optimizer')

        optimizer = property(_get_optimizer)
Ejemplo n.º 23
0
def split_core_active(one,
                      two,
                      ecore,
                      orb,
                      ncore,
                      nactive,
                      indextrans='tensordot'):
    '''Reduce a Hamiltonian to an active space

       Works only for restricted wavefunctions.

       **Arguments:**

       one/two
            One and two-electron integrals.

       ecore
            The core energy of the given Hamiltonian. In the case of a standard
            molecular system, this is the nuclear nuclear repulsion.

       orb
            The MO expansion coefficients. An Expansion instance. If None,
            integrals are assued to be already transformed into the mo basis
            and no transformation is carried out in this function.

       ncore
            The number of frozen core orbitals (int)

       nactive
            The number of active orbitals (int)

       **Optional arguments:**

       indextrans
            4-index transformation (str). One of ``tensordot``, ``einsum``

       **Returns** a tuple with three values:

       one_small
            The one-body operator in the small space

       two_small
            The two-body operator in the small space

       ecore
            The core energy, i.e. the sum of the given core energy and HF
            contributions from the core orbitals.
    '''
    #
    # Check type/option of arguments
    #
    check_type('ncore', ncore, int)
    check_type('nactive', nactive, int)
    check_options('indextrans', indextrans, 'tensordot', 'einsum')
    if ncore <= 0 or nactive <= 0:
        raise ValueError('ncore and nactive must be strictly positive.')
    if nactive + ncore > one.nbasis:
        raise ValueError('More active orbitals than basis functions.')

    #
    # Optional transformation to mo basis
    #
    if orb is None:
        one_mo = one
        two_mo = two
    else:
        # No need to check orb. This is done in transform_integrals function
        (one_mo, ), (two_mo, ) = transform_integrals(one, two, indextrans, orb)

    # Core energy
    norb = one.nbasis
    #   One body term
    ecore += 2 * one_mo.trace(0, ncore, 0, ncore)
    #   Direct part
    ecore += two_mo.slice_to_two('abab->ab', None, 2.0, True, 0, ncore, 0,
                                 ncore, 0, ncore, 0, ncore).sum()
    #   Exchange part
    ecore += two_mo.slice_to_two('abba->ab', None, -1.0, True, 0, ncore, 0,
                                 ncore, 0, ncore, 0, ncore).sum()

    # Active space one-body integrals
    one_mo_corr = one_mo.new()
    #   Direct part
    two_mo.contract_to_two('abcb->ac', one_mo_corr, 2.0, True, 0, norb, 0,
                           ncore, 0, norb, 0, ncore)
    #   Exchange part
    two_mo.contract_to_two('abbc->ac', one_mo_corr, -1.0, False, 0, norb, 0,
                           ncore, 0, ncore, 0, norb)
    one_mo.iadd(one_mo_corr, 1.0)
    #one_mo.iadd_t(one_mo_corr, 1.0)

    #
    # Store in smaller n-index objects
    #
    one_mo_small = one_mo.copy(ncore, ncore + nactive, ncore, ncore + nactive)
    two_mo_small = two_mo.copy(ncore, ncore + nactive, ncore, ncore + nactive,
                               ncore, ncore + nactive, ncore, ncore + nactive)

    # Done
    return one_mo_small, two_mo_small, ecore