Exemplo 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
Exemplo 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
Exemplo n.º 3
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
Exemplo n.º 4
0
    def assign_four_index_transform(self,
                                    ao_integrals,
                                    exp0,
                                    exp1=None,
                                    exp2=None,
                                    exp3=None,
                                    method='tensordot'):
        '''Perform four index transformation.

           **Arguments:**

           oa_integrals
                A CholeskyFourIndex with integrals in atomic orbitals.

           exp0
                A DenseExpansion object with molecular orbitals

           **Optional arguments:**

           exp1, exp2, exp3
                Can be provided to transform each index differently. See
                ``parse_four_index_transform_exps`` for details.

           method
                Either ``einsum`` or ``tensordot`` (default).
        '''
        check_type('ao_integrals', ao_integrals, CholeskyFourIndex)
        exp0, exp1, exp2, exp3 = parse_four_index_transform_exps(
            exp0, exp1, exp2, exp3, DenseExpansion)
        if method == 'einsum':
            if ao_integrals.is_decoupled or not (exp0 is exp1
                                                 and exp2 is exp3):
                self.decouple_array2()
                self._array2[:] = np.einsum('bi,kbd->kid', exp1.coeffs,
                                            ao_integrals._array2)
                self._array2[:] = np.einsum('dj,kid->kij', exp3.coeffs,
                                            self._array2)
            self._array[:] = np.einsum('ai,kac->kic', exp0.coeffs,
                                       ao_integrals._array)
            self._array[:] = np.einsum('cj,kic->kij', exp2.coeffs, self._array)
        elif method == 'tensordot':
            if ao_integrals.is_decoupled or not (exp0 is exp1
                                                 and exp2 is exp3):
                self.decouple_array2()
                self._array2[:] = np.tensordot(ao_integrals._array2,
                                               exp1.coeffs,
                                               axes=([1], [0]))
                self._array2[:] = np.tensordot(self._array2,
                                               exp3.coeffs,
                                               axes=([1], [0]))
            self._array[:] = np.tensordot(ao_integrals._array,
                                          exp0.coeffs,
                                          axes=([1], [0]))
            self._array[:] = np.tensordot(self._array,
                                          exp2.coeffs,
                                          axes=([1], [0]))
        else:
            raise ValueError(
                'The method must either be \'einsum\' or \'tensordot\'.')
Exemplo n.º 5
0
    def assign(self, other):
        """Assign with the contents of another object.

        Parameters
        ----------
        other : Orbitals
            Another Orbitals object
        """
        check_type('other', other, Orbitals)
        self._coeffs[:] = other._coeffs
        self._energies[:] = other._energies
        self._occupations[:] = other._occupations
Exemplo n.º 6
0
    def assign(self, other):
        """Assign with the contents of another object.

        Parameters
        ----------
        other : Orbitals
            Another Orbitals object
        """
        check_type('other', other, Orbitals)
        self._coeffs[:] = other._coeffs
        self._energies[:] = other._energies
        self._occupations[:] = other._occupations
Exemplo n.º 7
0
    def perm(self, a):
        '''Calculate the permament of a matrix

           **Arguements**

           a
                A np array
        '''
        check_type('matrix', a, np.ndarray)
        n = len(a)
        r = range(n)
        s = permutations(r)
        import math  # FIXME: fsum really needed for accuracy?
        return math.fsum(self.prod(a[i][sigma[i]] for i in r) for sigma in s)
Exemplo n.º 8
0
    def perm(self, a):
        '''Calculate the permament of a matrix

           **Arguements**

           a
                A np array
        '''
        check_type('matrix', a, np.ndarray)
        n = len(a)
        r = range(n)
        s = permutations(r)
        import math # FIXME: fsum really needed for accuracy?
        return math.fsum(self.prod(a[i][sigma[i]] for i in r) for sigma in s)
Exemplo n.º 9
0
    def assign(self, other):
        '''Assign with the contents of another object

           **Arguments:**

           other
                Another CholeskyFourIndex object.
        '''
        check_type('other', other, CholeskyFourIndex)
        self._array[:] = other._array
        if other._array is other._array2:
            self.reset_array2()
        else:
            self.decouple_array2()
            self._array2[:] = other._array2
Exemplo n.º 10
0
    def __init__(self, lf, occ_model, npairs=None, nvirt=None):
        '''
           **Arguments:**

           lf
                A LinalgFactory instance.

           occ_model
                Occupation model

           **Optional arguments:**

           npairs
                Number of electron pairs, if not specified,
                npairs = number of occupied orbitals

           nvirt
                Number of virtual orbitals, if not specified,
                nvirt = (nbasis-npairs)
        '''
        check_type('pairs', npairs, int, type(None))
        check_type('virtuals', nvirt, int, type(None))
        self._lf = lf
        self._nocc = occ_model.noccs[0]
        self._nbasis = lf.default_nbasis
        if npairs is None:
            npairs = occ_model.noccs[0]
        elif npairs >= lf.default_nbasis:
            raise ValueError(
                'Number of electron pairs (%i) larger than number of basis functions (%i)'
                % (npairs, self.nbasis))
        if nvirt is None:
            nvirt = (lf.default_nbasis - npairs)
        elif nvirt >= lf.default_nbasis:
            raise ValueError(
                'Number of virtuals (%i) larger than number of basis functions (%i)'
                % (nvirt, self.nbasis))
        self._npairs = npairs
        self._nvirt = nvirt
        self._cache = Cache()
        self._ecore = 0
        self._geminal = lf.create_two_index(npairs, nvirt)
        self._lagrange = lf.create_two_index(npairs, nvirt)
Exemplo n.º 11
0
    def __init__(self, lf, occ_model, npairs=None, nvirt=None):
        '''
           **Arguments:**

           lf
                A LinalgFactory instance.

           occ_model
                Occupation model

           **Optional arguments:**

           npairs
                Number of electron pairs, if not specified,
                npairs = number of occupied orbitals

           nvirt
                Number of virtual orbitals, if not specified,
                nvirt = (nbasis-npairs)
        '''
        check_type('pairs', npairs, int, type(None))
        check_type('virtuals', nvirt, int, type(None))
        self._lf = lf
        self._nocc = occ_model.noccs[0]
        self._nbasis = lf.default_nbasis
        if npairs is None:
            npairs = occ_model.noccs[0]
        elif npairs >= lf.default_nbasis:
            raise ValueError('Number of electron pairs (%i) larger than number of basis functions (%i)' %(npairs, self.nbasis))
        if nvirt is None:
            nvirt = (lf.default_nbasis-npairs)
        elif nvirt >= lf.default_nbasis:
            raise ValueError('Number of virtuals (%i) larger than number of basis functions (%i)' %(nvirt, self.nbasis))
        self._npairs = npairs
        self._nvirt = nvirt
        self._cache = Cache()
        self._ecore = 0
        self._geminal = lf.create_two_index(npairs, nvirt)
        self._lagrange = lf.create_two_index(npairs, nvirt)
Exemplo n.º 12
0
    def assign_four_index_transform(self, ao_integrals, exp0, exp1=None, exp2=None, exp3=None, method='tensordot'):
        '''Perform four index transformation.

           **Arguments:**

           oa_integrals
                A CholeskyFourIndex with integrals in atomic orbitals.

           exp0
                A DenseExpansion object with molecular orbitals

           **Optional arguments:**

           exp1, exp2, exp3
                Can be provided to transform each index differently. See
                ``parse_four_index_transform_exps`` for details.

           method
                Either ``einsum`` or ``tensordot`` (default).
        '''
        check_type('ao_integrals', ao_integrals, CholeskyFourIndex)
        exp0, exp1, exp2, exp3 = parse_four_index_transform_exps(exp0, exp1, exp2, exp3, DenseExpansion)
        if method == 'einsum':
            if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3):
                self.decouple_array2()
                self._array2[:] = np.einsum('bi,kbd->kid', exp1.coeffs, ao_integrals._array2)
                self._array2[:] = np.einsum('dj,kid->kij', exp3.coeffs, self._array2)
            self._array[:] = np.einsum('ai,kac->kic', exp0.coeffs, ao_integrals._array)
            self._array[:] = np.einsum('cj,kic->kij', exp2.coeffs, self._array)
        elif method == 'tensordot':
            if ao_integrals.is_decoupled or not (exp0 is exp1 and exp2 is exp3):
                self.decouple_array2()
                self._array2[:] = np.tensordot(ao_integrals._array2, exp1.coeffs, axes=([1],[0]))
                self._array2[:] = np.tensordot(self._array2, exp3.coeffs, axes=([1],[0]))
            self._array[:] = np.tensordot(ao_integrals._array, exp0.coeffs, axes=([1],[0]))
            self._array[:] = np.tensordot(self._array, exp2.coeffs, axes=([1],[0]))
        else:
            raise ValueError('The method must either be \'einsum\' or \'tensordot\'.')
Exemplo n.º 13
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']
Exemplo n.º 14
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']
Exemplo n.º 15
0
def parse_four_index_transform_exps(exp0, exp1, exp2, exp3, Class):
    '''Parse the optional arguments exp1, exp2 and exp3.

       **Arguments:**

       exp0, exp1, exp2, exp3
            Four sets of orbitals for the mo transformation. Some may be None
            but only the following not None combinations are allowed:

            * ``(exp0,)``: maintain eight-fold symmetry (if any)
            * ``(exp0, exp1)``: maintain four-fold symmetry (if any)
            * ``(exp0, exp2)``: maintain two-fold symmetry (if any)
            * ``(exp0, exp1, exp2, exp3)``: break all symmetry

       Class
            The expected class of the exps objects.


       **Returns:** exp0, exp1, exp2, exp3. (All not None)
    '''
    # Four supported situations
    if exp1 is None and exp2 is None and exp3 is None:
        # maintains eight-fold symmetry
        exp1 = exp0
        exp2 = exp0
        exp3 = exp0
    elif exp2 is None and exp3 is None:
        # maintains four-fold symmetry
        exp2 = exp0
        exp3 = exp1
    elif exp1 is None and exp3 is None:
        # maintains two-fold symmetry
        exp1 = exp0
        exp3 = exp2
    elif exp1 is None or exp2 is None or exp3 is None:
        # the only other allowed case is no symmetry.
        raise TypeError(
            'It is not clear how to interpret the optional arguments exp1, exp2 and exp3.'
        )
    check_type('exp0', exp0, Class)
    check_type('exp1', exp1, Class)
    check_type('exp2', exp2, Class)
    check_type('exp3', exp3, Class)
    return exp0, exp1, exp2, exp3
Exemplo n.º 16
0
def parse_four_index_transform_exps(exp0, exp1, exp2, exp3, Class):
    '''Parse the optional arguments exp1, exp2 and exp3.

       **Arguments:**

       exp0, exp1, exp2, exp3
            Four sets of orbitals for the mo transformation. Some may be None
            but only the following not None combinations are allowed:

            * ``(exp0,)``: maintain eight-fold symmetry (if any)
            * ``(exp0, exp1)``: maintain four-fold symmetry (if any)
            * ``(exp0, exp2)``: maintain two-fold symmetry (if any)
            * ``(exp0, exp1, exp2, exp3)``: break all symmetry

       Class
            The expected class of the exps objects.


       **Returns:** exp0, exp1, exp2, exp3. (All not None)
    '''
    # Four supported situations
    if exp1 is None and exp2 is None and exp3 is None:
        # maintains eight-fold symmetry
        exp1 = exp0
        exp2 = exp0
        exp3 = exp0
    elif exp2 is None and exp3 is None:
        # maintains four-fold symmetry
        exp2 = exp0
        exp3 = exp1
    elif exp1 is None and exp3 is None:
        # maintains two-fold symmetry
        exp1 = exp0
        exp3 = exp2
    elif exp1 is None or exp2 is None or exp3 is None:
        # the only other allowed case is no symmetry.
        raise TypeError('It is not clear how to interpret the optional arguments exp1, exp2 and exp3.')
    check_type('exp0', exp0, Class)
    check_type('exp1', exp1, Class)
    check_type('exp2', exp2, Class)
    check_type('exp3', exp3, Class)
    return exp0, exp1, exp2, exp3
Exemplo n.º 17
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
Exemplo n.º 18
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)
Exemplo n.º 19
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)
Exemplo n.º 20
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