Пример #1
0
    def __call__(self,X,Y=None,eval_gradient=False):
        """ Return the kernel k(X,Y) and optionally its gradient.

        """

        X = np.atleast_2d(X)
        a = _check_length_scale(X,self.a)
        if Y is None:
            dists = pdist(X/a,metric = 'sqeuclidean')
            K = np.exp(-0.5*dists)
            K = squareform(K)
            np.fill_diagonal(K,1)
        else:
            if eval_gradient:
                raise ValueError("Gradient can only be evaluated when Y is None")
            dists = cdist(X/a,Y/a,metric='sqeuclidean')
            K = np.exp(-0.5*dists)
        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                return K,np.empty((X.shape[0],X.shape[0],0))
            elif not self.anisotropic or a.shape[0] == 1:
                K_gradient = (K * squareform(dists))[:,:,np.newaxis]
                return K,K_gradient
            elif self.anisotropic:
                K_gradient = (X[:,np.newaxis,:] - X[np.newaxis,:,:])**2/(a**2)
                K-gradient *= K[...,np.newaxis]
                return K,K_gradient
        
        else:
            return K
    def __call__(self, XX1, XX2=None, eval_gradient=False):
        """Return the kernel k(XX1, XX2) and optionally its gradient.

        Parameters
        ----------
        XX1 : array, shape (n_samples_XX1, n_features)
            Left argument of the returned kernel k(XX1, XX2)

        XX2 : array, shape (n_samples_XX2, n_features), (optional, default=None)
            Right argument of the returned kernel k(XX1, XX2). If None, 
            k(XX1, XX1) is evaluated instead.

        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when XX2 is None.

        Returns
        -------
        K : array, shape (n_samples_XX1, n_samples_XX2)
            Kernel k(XX1, XX2)

        K_gradient : array (opt.), shape (n_samples_XX1, n_samples_XX1, n_dims)
            The gradient of the kernel k(XX1, XX1) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """
        XX1 = np.atleast_2d(XX1)
        length_scale = _check_length_scale(XX1, self.length_scale)
        if XX2 is None:
            K = full_kernel(XX1,
                            length_scale,
                            self.n_XX_func,
                            return_code=self.return_code)
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when XX2 is None.")
            K = full_kernel(XX1, length_scale, self.n_XX_func, XX2,
                            self.return_code)
        print(K.shape, 'KK')
        if not eval_gradient:
            return K

        if self.hyperparameter_length_scale.fixed:
            # Hyperparameter l kept fixed
            length_scale_gradient = np.empty((K.shape[0], K.shape[1], 0))
        else:
            # approximate gradient numerically
            def f(gamma):  # helper function
                return full_kernel(XX1,
                                   gamma,
                                   self.n_XX_func,
                                   return_code=self.return_code)

            length_scale = np.atleast_1d(length_scale)
            length_scale_gradient = _approx_fprime(length_scale, f, 1e-8)
        return K, length_scale_gradient
Пример #3
0
    def __call__(self, X, Y=None, eval_gradient=False):
        """Return the kernel k(X, Y) and optionally its gradient.

        Parameters
        ----------
        X : array, shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)

        Y : array, shape (n_samples_Y, n_features), (optional, default=None)
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.

        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.

        Returns
        -------
        K : array, shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)

        K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """
        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
            dists = pdist(X / length_scale, metric=MMetric)
            K = np.exp(-.5 * dists)
            # convert from upper-triangular matrix to square matrix
            K = squareform(K)
            np.fill_diagonal(K, 1)
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = cdist(X / length_scale, Y / length_scale, metric=MMetric)
            K = np.exp(-.5 * dists)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = \
                    (K * squareform(dists))[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                # We need to recompute the pairwise dimension-wise distances
                K_gradient = (X[:, np.newaxis, :] - X[np.newaxis, :, :]) ** 2 \
                    / (length_scale ** 2)
                K_gradient *= K[..., np.newaxis]
                return K, K_gradient
        else:
            return K
    def __call__(self, X, Y=None, eval_gradient=False):
        
        X = np.atleast_2d(X)
        
        qq=self.indx
        xbest=X[qq,]
    

        
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
                
            K=np.zeros((X.shape[0],X.shape[0]))
            for i in range(X.shape[0]):
                for j in range(X.shape[0]):
                    dists1 = cdist([X[i,]]/length_scale,[xbest]/length_scale, metric='sqeuclidean')[0,0]
                    dists2 = cdist([X[j,]]/length_scale,[xbest]/length_scale, metric='sqeuclidean')[0,0]
                    dists3 = np.abs(dists1-dists2)                   
                    K[i,j]=np.exp(-.5 * dists1*dists2)*np.exp(-.5 * dists3)
 
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            K=np.zeros((X.shape[0],Y.shape[0]))
            for i in range(X.shape[0]):
                for j in range(Y.shape[0]):
                    abs1=np.abs(np.array([X[i,]])-np.array([xbest]))
                    abs2=np.abs(np.array([Y[j,]])-np.array([xbest])) 
                    dists = cdist(abs1/length_scale,abs2/length_scale,metric='sqeuclidean')[0,0]
   #                 dists1 = cdist([X[i,]]/length_scale,[xbest]/length_scale, metric='minkowski',p=1)[0,0]
    #                dists2 = cdist([Y[j,]]/length_scale,[xbest]/length_scale, metric='minkowski',p=1)[0,0]
    #                dists3 = np.abs(dists1-dists2)                   
                    K[i,j]=np.exp(-.5 * dists)        
            
            
  #          dists = cdist(X / length_scale, Y / length_scale,
  #                        metric='sqeuclidean')
 #           K = np.exp(-.5 * dists)
  #          print(K.shape)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = \
                    (K * squareform(dists))[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                # We need to recompute the pairwise dimension-wise distances
                K_gradient = (X[:, np.newaxis, :] - X[np.newaxis, :, :]) ** 2 \
                    / (length_scale ** 2)
                K_gradient *= K[..., np.newaxis]
                return K, K_gradient
        else:
            return K
Пример #5
0
 def __call__(self, X, Y=None, eval_gradient=False):
     """Return the kernel k(X, Y) and optionally its gradient.
     Parameters
    ----------
    X : array, shape (n_samples_X, n_features)
        Left argument of the returned kernel k(X, Y)
     Y : array, shape (n_samples_Y, n_features), (optional, default=None)
        Right argument of the returned kernel k(X, Y). If None, k(X, X)
        if evaluated instead.
     eval_gradient : bool (optional, default=False)
        Determines whether the gradient with respect to the kernel
        hyperparameter is determined. Only supported when Y is None.
     Returns
    -------
    K : array, shape (n_samples_X, n_samples_Y)
        Kernel k(X, Y)
     K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
        The gradient of the kernel k(X, X) with respect to the
        hyperparameter of the kernel. Only returned when eval_gradient
        is True.
    """
     X = np.atleast_2d(X)
     self.c = _check_length_scale(X, self.c)
     if self.c is 0:
         Xsub = X
     else:
         Xsub = X - self.c
     if Y is None:
         K = np.inner(Xsub, Xsub)
     else:
         if eval_gradient:
             raise ValueError(
                 "Gradient can only be evaluated when Y is None.")
         K = np.inner(Xsub, Y - self.c)
     if eval_gradient:
         if self.hyperparameter_c.fixed:
             c_gradient = np.empty((X.shape[0], X.shape[0], 0))
         else:
             if not self.non_uniform_offset:
                 gradient_mat = np.inner(np.ones(X.shape), Xsub)
                 c_gradient = -self.c * (gradient_mat + gradient_mat.T)
                 c_gradient = c_gradient[:, :, np.newaxis]
             else:
                 c_gradient = []
                 for i, c in enumerate(self.c):
                     gradient_mat = np.vstack([Xsub[:, i]] * X.shape[0])
                     c_gradient.append(c * (gradient_mat + gradient_mat.T))
                 c_gradient = -np.array(c_gradient)
                 c_gradient = np.rollaxis(c_gradient, 0, 3)
         return K, c_gradient
     else:
         return K
Пример #6
0
    def __call__(self, X, Y=None, eval_gradient=False):
        mols = data['Smiles'].apply(Chem.MolFromSmiles)
        X = mols.apply(torsionFingerprint)
        X = np.array(list(X))
        st = StandardScaler()
        X = st.fit_transform(X)
        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
            dists = pdist(X / length_scale, metric='jaccard')
            K = np.exp(-.5 * dists)
            # convert from upper-triangular matrix to square matrix
            K = squareform(K)
            np.fill_diagonal(K, 1)
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = cdist(X / length_scale,
                          Y / length_scale,
                          metric='sqeuclidean')
            K = np.exp(-.5 * dists)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = \
                    (K * squareform(dists))[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                # We need to recompute the pairwise dimension-wise distances
                K_gradient = (X[:, np.newaxis, :] - X[np.newaxis, :, :]) ** 2 \
                    / (length_scale ** 2)
                K_gradient *= K[..., np.newaxis]
                return K, K_gradient
        else:
            return K
Пример #7
0
    def __call__(self, X, Y=None, eval_gradient=False):
        if eval_gradient and Y is not None:
            X = np.atleast_2d(X)

            length_scale = _check_length_scale(X, self.length_scale)
            dists = cdist(X / length_scale,
                          Y / length_scale,
                          metric='sqeuclidean')

            K = np.exp(-.5 * dists)

            if self.hyperparameter_length_scale.fixed:
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = (K * dists)[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                K_gradient = (X[:, np.newaxis, :] - Y[np.newaxis, :, :]) ** 2 \
                             / (length_scale ** 2)
                K_gradient *= K[..., np.newaxis]
                return K, K_gradient

        else:
            return super().__call__(X, Y, eval_gradient)
Пример #8
0
    def _call(
        self,
        X: np.ndarray,
        Y: Optional[np.ndarray] = None,
        eval_gradient: bool = False,
        active: Optional[np.ndarray] = None,
    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:
        """Return the kernel k(X, Y) and optionally its gradient.

        Parameters
        ----------
        X : [array-like, shape=(n_samples_X, n_features)]
            Left argument of the returned kernel k(X, Y)
        Y : [array-like, shape=(n_samples_Y, n_features) or None(default)]
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.
        eval_gradient : [bool, False(default)]
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.
        active : np.ndarray (n_samples_X, n_features) (optional)
            Boolean array specifying which hyperparameters are active.

        Returns
        -------
        K : [array-like, shape=(n_samples_X, n_samples_Y)]
            Kernel k(X, Y)

        K_gradient : [array-like, shape=(n_samples_X, n_samples_X, n_dims)]
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.

        Note
        ----
        Code partially copied from skopt (https://github.com/scikit-optimize).
        Made small changes to only compute necessary values and use scikit-learn helper functions.
        """

        X = np.atleast_2d(X)
        length_scale = kernels._check_length_scale(X, self.length_scale)

        if Y is None:
            Y = X
        elif eval_gradient:
            raise ValueError("gradient can be evaluated only when Y != X")
        else:
            Y = np.atleast_2d(Y)

        indicator = np.expand_dims(X, axis=1) != Y
        K = (-1 / (2 * length_scale**2) * indicator).sum(axis=2)
        K = np.exp(K)

        if active is not None:
            K = K * active

        if eval_gradient:
            # dK / d theta = (dK / dl) * (dl / d theta)
            # theta = log(l) => dl / d (theta) = e^theta = l
            # dK / d theta = l * dK / dl

            # dK / dL computation
            if np.iterable(length_scale) and length_scale.shape[0] > 1:
                grad = np.expand_dims(K, axis=-1) * np.array(indicator,
                                                             dtype=np.float32)
            else:
                grad = np.expand_dims(K * np.sum(indicator, axis=2), axis=-1)

            grad *= 1 / length_scale**3

            return K, grad
        return K
Пример #9
0
    def _call(
        self,
        X: np.ndarray,
        Y: Optional[np.ndarray] = None,
        eval_gradient: bool = False,
        active: Optional[np.ndarray] = None,
    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:
        """Return the kernel k(X, Y) and optionally its gradient.

        Parameters
        ----------
        X : array, shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)
        Y : array, shape (n_samples_Y, n_features), (optional, default=None)
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.
        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.
        active : np.ndarray (n_samples_X, n_features) (optional)
            Boolean array specifying which hyperparameters are active.

        Returns
        -------
        K : array, shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)
        K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """

        X = np.atleast_2d(X)
        length_scale = kernels._check_length_scale(X, self.length_scale)

        if Y is None:
            dists = scipy.spatial.distance.pdist(X / length_scale,
                                                 metric="sqeuclidean")
            K = np.exp(-0.5 * dists)
            # convert from upper-triangular matrix to square matrix
            K = scipy.spatial.distance.squareform(K)
            np.fill_diagonal(K, 1)
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = scipy.spatial.distance.cdist(X / length_scale,
                                                 Y / length_scale,
                                                 metric="sqeuclidean")
            K = np.exp(-0.5 * dists)

        if active is not None:
            K = K * active

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = (
                    K * scipy.spatial.distance.squareform(dists))[:, :,
                                                                  np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                # We need to recompute the pairwise dimension-wise distances
                K_gradient = (X[:, np.newaxis, :] -
                              X[np.newaxis, :, :])**2 / (length_scale**2)
                K_gradient *= K[..., np.newaxis]
                return K, K_gradient

        return K
Пример #10
0
    def _call(
        self,
        X: np.ndarray,
        Y: Optional[np.ndarray] = None,
        eval_gradient: bool = False,
        active: Optional[np.ndarray] = None,
    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:
        """Return the kernel k(X, Y) and optionally its gradient.

        Parameters
        ----------
        X : array, shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)
        Y : array, shape (n_samples_Y, n_features), (optional, default=None)
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.
        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.
        active : np.ndarray (n_samples_X, n_features) (optional)
            Boolean array specifying which hyperparameters are active.

        Returns
        -------
        K : array, shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)
        K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """

        X = np.atleast_2d(X)
        length_scale = kernels._check_length_scale(X, self.length_scale)

        if Y is None:
            dists = scipy.spatial.distance.pdist(X / length_scale,
                                                 metric="euclidean")
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = scipy.spatial.distance.cdist(X / length_scale,
                                                 Y / length_scale,
                                                 metric="euclidean")

        if self.nu == 0.5:
            K = np.exp(-dists)
        elif self.nu == 1.5:
            K = dists * math.sqrt(3)
            K = (1.0 + K) * np.exp(-K)
        elif self.nu == 2.5:
            K = dists * math.sqrt(5)
            K = (1.0 + K + K**2 / 3.0) * np.exp(-K)
        else:  # general case; expensive to evaluate
            K = dists
            K[K == 0.0] += np.finfo(float).eps  # strict zeros result in nan
            tmp = math.sqrt(2 * self.nu) * K
            K.fill((2**(1.0 - self.nu)) / scipy.special.gamma(self.nu))
            K *= tmp**self.nu
            K *= scipy.special.kv(self.nu, tmp)

        if Y is None:
            # convert from upper-triangular matrix to square matrix
            K = scipy.spatial.distance.squareform(K)
            np.fill_diagonal(K, 1)

        if active is not None:
            K = K * active

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                K_gradient = np.empty((X.shape[0], X.shape[0], 0))
                return K, K_gradient

            # We need to recompute the pairwise dimension-wise distances
            if self.anisotropic:
                D = (X[:, np.newaxis, :] -
                     X[np.newaxis, :, :])**2 / (length_scale**2)
            else:
                D = scipy.spatial.distance.squareform(dists**2)[:, :,
                                                                np.newaxis]

            if self.nu == 0.5:
                K_gradient = (K[..., np.newaxis] * D /
                              np.sqrt(D.sum(2))[:, :, np.newaxis])
                K_gradient[~np.isfinite(K_gradient)] = 0
            elif self.nu == 1.5:
                K_gradient = 3 * D * np.exp(-np.sqrt(3 * D.sum(-1)))[
                    ..., np.newaxis]
            elif self.nu == 2.5:
                tmp = np.sqrt(5 * D.sum(-1))[..., np.newaxis]
                K_gradient = 5.0 / 3.0 * D * (tmp + 1) * np.exp(-tmp)
            else:
                # original sklearn code would approximate gradient numerically, but this would violate our assumption
                # that the kernel hyperparameters are not changed within __call__
                raise ValueError(self.nu)

            if not self.anisotropic:
                return K, K_gradient[:, :].sum(-1)[:, :, np.newaxis]
            else:
                return K, K_gradient
        else:
            return K
Пример #11
0
    def __call__(self, X, Y=None, eval_gradient=False):
        """Return the kernel k(X, Y) and optionally its gradient.

        Parameters
        ----------
        X : array, shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)

        Y : array, shape (n_samples_Y, n_features), (optional, default=None)
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.

        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.

        Returns
        -------
        K : array, shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)

        K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """
        from scipy.spatial.distance import pdist, cdist, squareform
        from scipy import special

        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
            dists = pdist(X, metric='euclidean')
            Filter = (dists != 0.)
            K = np.zeros_like(dists)
            K[Filter] = ((dists[Filter]/length_scale)**(5./6.) *
                         special.kv(5./6.,2*np.pi*dists[Filter]/length_scale))
            K = squareform(K)

            lim0 = special.gamma(5./6.) / (2 * (np.pi**(5./6.)))
            np.fill_diagonal(K, lim0)
            K /= lim0
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")

            dists = cdist(X, Y, metric='euclidean')
            Filter = (dists != 0.)
            K = np.zeros_like(dists)
            K[Filter] = ((dists[Filter]/length_scale)**(5./6.) *
                       special.kv(5./6.,2*np.pi*dists[Filter]/length_scale))
            lim0 = special.gamma(5./6.) / (2 * (np.pi**(5./6.)))
            if np.sum(Filter) != len(K[0])*len(K[:,0]):
                K[~Filter] = lim0
            K /= lim0

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], X.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                K_gradient = (K * squareform(dists))[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:
                raise ValueError(
                    "Gradient can only be evaluated with isotropic VonKarman kernel for the moment.")
        else:
            return K
    def __call__(self, X, Y=None, eval_gradient=False):
        """Return the kernel k(X, Y) and optionally its gradient.
        Parameters
        ----------
        X : ndarray of shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)
        Y : ndarray of shape (n_samples_Y, n_features), default=None
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.
        eval_gradient : bool, default=False
            Determines whether the gradient with respect to the log of
            the kernel hyperparameter is computed.
            Only supported when Y is None.
        Returns
        -------
        K : ndarray of shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)
        K_gradient : ndarray of shape (n_samples_X, n_samples_X, n_dims), \
                optional
            The gradient of the kernel k(X, X) with respect to the log of the
            hyperparameter of the kernel. Only returned when `eval_gradient`
            is True.
        """

        X = np.round(X)
        if not Y is None:
            Y = np.round(Y)

        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
            dists = pdist(X / length_scale, metric='euclidean')
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = cdist(X / length_scale,
                          Y / length_scale,
                          metric='euclidean')

        if self.nu == 0.5:
            K = np.exp(-dists)
        elif self.nu == 1.5:
            K = dists * math.sqrt(3)
            K = (1. + K) * np.exp(-K)
        elif self.nu == 2.5:
            K = dists * math.sqrt(5)
            K = (1. + K + K**2 / 3.0) * np.exp(-K)
        elif self.nu == np.inf:
            K = np.exp(-dists**2 / 2.0)
        else:  # general case; expensive to evaluate
            K = dists
            K[K == 0.0] += np.finfo(float).eps  # strict zeros result in nan
            tmp = (math.sqrt(2 * self.nu) * K)
            K.fill((2**(1. - self.nu)) / gamma(self.nu))
            K *= tmp**self.nu
            K *= kv(self.nu, tmp)

        if Y is None:
            # convert from upper-triangular matrix to square matrix
            K = squareform(K)
            np.fill_diagonal(K, 1)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                K_gradient = np.empty((X.shape[0], X.shape[0], 0))
                return K, K_gradient

            # We need to recompute the pairwise dimension-wise distances
            if self.anisotropic:
                D = (X[:, np.newaxis, :] - X[np.newaxis, :, :])**2 \
                    / (length_scale ** 2)
            else:
                D = squareform(dists**2)[:, :, np.newaxis]

            if self.nu == 0.5:
                denominator = np.sqrt(D.sum(axis=2))[:, :, np.newaxis]
                K_gradient = K[..., np.newaxis] * \
                    np.divide(D, denominator, where=denominator != 0)
            elif self.nu == 1.5:
                K_gradient = \
                    3 * D * np.exp(-np.sqrt(3 * D.sum(-1)))[..., np.newaxis]
            elif self.nu == 2.5:
                tmp = np.sqrt(5 * D.sum(-1))[..., np.newaxis]
                K_gradient = 5.0 / 3.0 * D * (tmp + 1) * np.exp(-tmp)
            elif self.nu == np.inf:
                K_gradient = D * K[..., np.newaxis]
            else:
                # approximate gradient numerically
                def f(theta):  # helper function
                    return self.clone_with_theta(theta)(X, Y)

                return K, _approx_fprime(self.theta, f, 1e-10)

            if not self.anisotropic:
                return K, K_gradient[:, :].sum(-1)[:, :, np.newaxis]
            else:
                return K, K_gradient
        else:
            return K
Пример #13
0
    def __call__(self, X, Y=None, eval_gradient=False):
        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        if Y is None:
            dists = pdist(X / length_scale, metric='euclidean')
        else:
            if eval_gradient:
                raise ValueError(
                    "Gradient can only be evaluated when Y is None.")
            dists = cdist(X / length_scale,
                          Y / length_scale,
                          metric='euclidean')

        if self.nu == 0.5:
            K = np.exp(-dists)
        elif self.nu == 1.5:
            K = dists * math.sqrt(3)
            K = (1. + K) * np.exp(-K)
        elif self.nu == 2.5:
            K = dists * math.sqrt(5)
            K = (1. + K + K**2 / 3.0) * np.exp(-K)
        else:  # general case; expensive to evaluate
            K = dists
            K[K == 0.0] += np.finfo(float).eps  # strict zeros result in nan
            tmp = (math.sqrt(2 * self.nu) * K)
            K.fill((2**(1. - self.nu)) / gamma(self.nu))
            K *= tmp**self.nu
            K *= kv(self.nu, tmp)

        if Y is None:
            # convert from upper-triangular matrix to square matrix
            K = squareform(K)
            np.fill_diagonal(K, 1)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                K_gradient = np.empty((X.shape[0], X.shape[0], 0))
                return K, K_gradient

            # We need to recompute the pairwise dimension-wise distances
            if self.anisotropic:
                D = (X[:, np.newaxis, :] - X[np.newaxis, :, :])**2 \
                    / (length_scale ** 2)
            else:
                D = squareform(dists**2)[:, :, np.newaxis]

            if self.nu == 0.5:
                K_gradient = safe_divide(K[..., np.newaxis] * D,
                                         np.sqrt(D.sum(2))[:, :, np.newaxis])
                K_gradient[~np.isfinite(K_gradient)] = 0
            elif self.nu == 1.5:
                K_gradient = \
                    3 * D * np.exp(-np.sqrt(3 * D.sum(-1)))[..., np.newaxis]
            elif self.nu == 2.5:
                tmp = np.sqrt(5 * D.sum(-1))[..., np.newaxis]
                K_gradient = 5.0 / 3.0 * D * (tmp + 1) * np.exp(-tmp)
            else:
                # approximate gradient numerically
                def f(theta):  # helper function
                    return self.clone_with_theta(theta)(X, Y)

                return K, _approx_fprime(self.theta, f, 1e-10)

            if not self.anisotropic:
                return K, K_gradient[:, :].sum(-1)[:, :, np.newaxis]
            else:
                return K, K_gradient
        else:
            return K
Пример #14
0
    def __call__(self, X, Y=None, dx=0, dy=0, eval_gradient=False):
        """Return the kernel k(X, Y) and optionally its gradient.
        Parameters
        ----------
        X : array, shape (n_samples_X, n_features)
            Left argument of the returned kernel k(X, Y)
        Y : array, shape (n_samples_Y, n_features), (optional, default=None)
            Right argument of the returned kernel k(X, Y). If None, k(X, X)
            if evaluated instead.
        eval_gradient : bool (optional, default=False)
            Determines whether the gradient with respect to the kernel
            hyperparameter is determined. Only supported when Y is None.
        Returns
        -------
        K : array, shape (n_samples_X, n_samples_Y)
            Kernel k(X, Y)
        K_gradient : array (opt.), shape (n_samples_X, n_samples_X, n_dims)
            The gradient of the kernel k(X, X) with respect to the
            hyperparameter of the kernel. Only returned when eval_gradient
            is True.
        """
        # X = atoms_X.get_positions()
        # if atoms_Y is None:
        #     Y = X
        # else:
        #     Y = atoms_Y.get_positions()
        X = np.atleast_2d(X)
        length_scale = _check_length_scale(X, self.length_scale)
        dists = cdist(X / length_scale, Y / length_scale, metric='sqeuclidean')
        K = np.exp(-.5 * dists)

        if not self.anisotropic or length_scale.shape[0] == 1:
            if dx != 0 or dy != 0:
                if dx == dy:
                    K = K * (1 -
                             np.subtract.outer(X[:, dx - 1].T, Y[:, dx - 1])**2
                             / length_scale**2) / length_scale**2  # J_ii
                elif dx == 0:  # and dy != 0:
                    K = K * np.subtract.outer(
                        X[:, dy - 1].T, Y[:, dy - 1]) / length_scale**2  # G
                elif dy == 0:  # and dx != 0:
                    K = -K * np.subtract.outer(
                        X[:, dx - 1].T, Y[:,
                                          dx - 1]) / length_scale**2  # K_prime
                else:
                    K = -K * np.subtract.outer(
                        X[:, dx - 1].T, Y[:, dx - 1]) * np.subtract.outer(
                            X[:, dy - 1].T,
                            Y[:, dy - 1]) / length_scale**4  # J_ij
        else:
            if dx != 0 or dy != 0:
                if dx == dy:
                    K = K * (
                        1 - np.subtract.outer(X[:, dx - 1].T, Y[:, dx - 1])**2
                        / length_scale[dx - 1]**2) / length_scale[dx - 1]**2
                elif dx == 0:
                    K = K * np.subtract.outer(
                        X[:, dy - 1].T, Y[:, dy - 1]) / length_scale[dy - 1]**2
                elif dy == 0:
                    K = -K * np.subtract.outer(
                        X[:, dx - 1].T, Y[:, dx - 1]) / length_scale[dx - 1]**2
                else:
                    K = -K * np.subtract.outer(
                        X[:, dx - 1].T, Y[:, dx - 1]) * np.subtract.outer(
                            X[:, dy - 1].T,
                            Y[:, dy - 1]) / (length_scale[dx - 1]**2 *
                                             length_scale[dy - 1]**2)

        if eval_gradient:
            if self.hyperparameter_length_scale.fixed:
                # Hyperparameter l kept fixed
                return K, np.empty((X.shape[0], Y.shape[0], 0))
            elif not self.anisotropic or length_scale.shape[0] == 1:
                if dx == 0 and dy == 0:
                    # K_gradient = (K * dists)[:, :, np.newaxis]
                    K_gradient = (K * dists)[:, :, np.newaxis] / length_scale
                elif dx != 0 and dy == 0:
                    # K_gradient = (K * (dists - 2))[:, :, np.newaxis]
                    K_gradient = (K *
                                  (dists - 2))[:, :, np.newaxis] / length_scale
                elif dy != 0 and dx == 0:
                    # K_gradient = (K * (dists - 2))[:, :, np.newaxis]
                    K_gradient = (K *
                                  (dists - 2))[:, :, np.newaxis] / length_scale
                    # K_gradient = (
                    #     K * (dists/length_scale**2 - 2/length_scale**2)
                    #     )[:, :, np.newaxis]
                else:
                    if dx == dy:
                        # K_gradient = (
                        #     K * (dists - 4) + 2 * np.exp(-0.5*dists) /
                        #     length_scale**2)[:, :, np.newaxis]
                        K_gradient = (
                            K * (dists - 4) + 2 * np.exp(-0.5 * dists) /
                            length_scale**2)[:, :, np.newaxis] / length_scale
                        # K_gradient = (
                        #     np.exp(-.5 * dists) / length_scale ** 2 *
                        #     (5*dists - 2 - dists **2))[:, :, np.newaxis]
                        # K_gradient = (
                        #     np.exp(-0.5*dists)*(
                        #         dists**2/length_scale**3 -
                        #         1./length_scale**5 -
                        #         4*(dists-1/length_scale**3) -
                        #         2/length_scale**3))[:, :, np.newaxis]
                    else:
                        # K_gradient = (K * (dists - 4))[:, :, np.newaxis]
                        K_gradient = (K *
                                      (dists - 4))[:, :,
                                                   np.newaxis] / length_scale
                        # K_gradient = (
                        #      -np.exp(-.5 * dists) * dists/length_scale**2 *
                        #      (4 - dists))[:, :, np.newaxis]
                        # K_gradient = (
                        #     np.exp(-.5 * dists) * dists**2 / length_scale**3
                        #     * (dists**2 - 4))[:, :, np.newaxis]
                return K, K_gradient
            elif self.anisotropic:

                # We need to recompute the pairwise dimension-wise distances
                grad = (X[:, np.newaxis, :] -
                        Y[np.newaxis, :, :])**2 / (length_scale**2)
                if dx == 0 and dy == 0:
                    K_gradient = grad * K[..., np.newaxis]

                elif (dx != 0 and dy == 0):
                    K_gradient = grad * K[..., np.newaxis]
                    K_gradient[:, :, dx - 1] = K_gradient[:, :, dx - 1] - 2 * K
                elif (dy != 0 and dx == 0):
                    K_gradient = grad * K[..., np.newaxis]
                    K_gradient[:, :, dy - 1] = K_gradient[:, :, dy - 1] - 2 * K
                else:
                    if dx == dy:
                        K_gradient = grad * K[..., np.newaxis]
                        K_gradient[:, :, dx - 1] = (
                            K_gradient[:, :, dx - 1] - np.exp(-0.5 * dists) *
                            (2 / length_scale[dx - 1]**2 -
                             4 * grad[:, :, dx - 1] / length_scale[dx - 1]**2))
                    else:
                        K_gradient = grad * K[..., np.newaxis]
                        K_gradient[:, :,
                                   dx - 1] = (K_gradient[:, :, dx - 1] - 2 * K)
                        K_gradient[:, :,
                                   dy - 1] = (K_gradient[:, :, dy - 1] - 2 * K)
                return K, K_gradient
        else:
            return K