# Path: reggie/core/domains.py
# POSITIVE = 'positive'
# 
# Path: reggie/utils/misc.py
# def rstate(rng=None):
#     """
#     Return a RandomState object. This is just a simple wrapper such that if rng
#     is already an instance of RandomState it will be passed through, otherwise
#     it will create a RandomState object using rng as its seed.
#     """
#     if not isinstance(rng, np.random.RandomState):
#         rng = np.random.RandomState(rng)
#     return rng
# 
# Path: reggie/kernels/_core.py
# class RealKernel(Kernel):
#     """
#     Kernel defined over a real-valued input space.
#     """
#     def get_gradx(self, X1, X2=None):
#         """
#         Compute the gradient of the kernel k(x,y) with respect to the first
#         input x, and evaluate it on input points X1 and X2.
#         """
#         raise NotImplementedError
# 
# Path: reggie/kernels/_distances.py
# def rescale(ell, X1, X2=None):
#     """
#     Rescale the input data contained in X1 and X2 with lengthscales ell. Return
#     the tuple of rescaled data, or if X2 is None return (X1, None).
#     """
#     X1 = (X1 / ell)
#     X2 = (X2 / ell) if (X2 is not None) else None
#     return X1, X2
# 
# def dist(X1, X2=None, metric='sqeuclidean'):
#     """
#     Compute the pairwise distances between input data contained in X1 and X2
#     with some given metric (passed directly to scipy's cdist). If X2 is None
#     then compute the distances between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     return ssd.cdist(X1, X2, metric)
# 
# def dist_foreach(X1, X2=None, metric='sqeuclidean'):
#     """
#     Return a generator which yields the pairwise distances between each
#     dimension of the data contained in X1 and X2.  If X2 is None then compute
#     the distances between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     for i in xrange(X1.shape[1]):
#         yield ssd.cdist(X1[:, i, None], X2[:, i, None], metric)
# 
# def diff(X1, X2=None):
#     """
#     Compute the pairwise differences between input data contained in X1 and X2.
#     If X2 is None then compute the differences between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     return X1[:, None, :] - X2[None, :, :]


import numpy as np
from ..core.domains import POSITIVE
from ..utils.misc import rstate
from ._core import RealKernel
from ._distances import rescale, dist, dist_foreach, diff
        self._iso = ndim is not None
        self.ndim = ndim if self._iso else self._ell.size

    def __info__(self):
        info = []
        info.append(('rho', self._rho))
        info.append(('ell', self._ell))
        if self._iso:
            info.append(('ndim', self.ndim))
        return info

    def get_kernel(self, X1, X2=None):
        X1, X2 = rescale(self._ell, X1, X2)
        D = dist(X1, X2)
        K = self._rho * np.exp(-D/2)
        return K

    def get_dkernel(self, X1):
        return np.full(len(X1), self._rho)

    def get_grad(self, X1, X2=None):
        X1, X2 = rescale(self._ell, X1, X2)
        D = dist(X1, X2)
        E = np.exp(-D/2)
        K = self._rho * E

        yield E                                 # derivative wrt rho
        if self._iso:
            yield K * D / self._ell             # derivative wrt ell (iso)
        else:

# Path: reggie/core/domains.py
# POSITIVE = 'positive'
# 
# Path: reggie/utils/misc.py
# def rstate(rng=None):
#     """
#     Return a RandomState object. This is just a simple wrapper such that if rng
#     is already an instance of RandomState it will be passed through, otherwise
#     it will create a RandomState object using rng as its seed.
#     """
#     if not isinstance(rng, np.random.RandomState):
#         rng = np.random.RandomState(rng)
#     return rng
# 
# Path: reggie/kernels/_core.py
# class RealKernel(Kernel):
#     """
#     Kernel defined over a real-valued input space.
#     """
#     def get_gradx(self, X1, X2=None):
#         """
#         Compute the gradient of the kernel k(x,y) with respect to the first
#         input x, and evaluate it on input points X1 and X2.
#         """
#         raise NotImplementedError
# 
# Path: reggie/kernels/_distances.py
# def rescale(ell, X1, X2=None):
#     """
#     Rescale the input data contained in X1 and X2 with lengthscales ell. Return
#     the tuple of rescaled data, or if X2 is None return (X1, None).
#     """
#     X1 = (X1 / ell)
#     X2 = (X2 / ell) if (X2 is not None) else None
#     return X1, X2
# 
# def dist(X1, X2=None, metric='sqeuclidean'):
#     """
#     Compute the pairwise distances between input data contained in X1 and X2
#     with some given metric (passed directly to scipy's cdist). If X2 is None
#     then compute the distances between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     return ssd.cdist(X1, X2, metric)
# 
# def dist_foreach(X1, X2=None, metric='sqeuclidean'):
#     """
#     Return a generator which yields the pairwise distances between each
#     dimension of the data contained in X1 and X2.  If X2 is None then compute
#     the distances between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     for i in xrange(X1.shape[1]):
#         yield ssd.cdist(X1[:, i, None], X2[:, i, None], metric)
# 
# def diff(X1, X2=None):
#     """
#     Compute the pairwise differences between input data contained in X1 and X2.
#     If X2 is None then compute the differences between X1 and itself.
#     """
#     X2 = X1 if (X2 is None) else X2
#     return X1[:, None, :] - X2[None, :, :]


# Path: reggie/kernels/se.py
import numpy as np
from ..core.domains import POSITIVE
from ..utils.misc import rstate
from ._core import RealKernel
from ._distances import rescale, dist, dist_foreach, diff

        self._iso = ndim is not None
        self.ndim = ndim if self._iso else self._ell.size

    def __info__(self):
        info = []
        info.append(('rho', self._rho))
        info.append(('ell', self._ell))
        if self._iso:
            info.append(('ndim', self.ndim))
        return info

    def get_kernel(self, X1, X2=None):
        X1, X2 = rescale(self._ell, X1, X2)
        D = dist(X1, X2)
        K = self._rho * np.exp(-D/2)
        return K

    def get_dkernel(self, X1):
        return np.full(len(X1), self._rho)

    def get_grad(self, X1, X2=None):
        X1, X2 = rescale(self._ell, X1, X2)
        D = dist(X1, X2)
        E = np.exp(-D/2)
        K = self._rho * E

        yield E                                 # derivative wrt rho
        if self._iso:
            yield K * D / self._ell             # derivative wrt ell (iso)
        else:

            for i, D in enumerate(dist_foreach(X1, X2)):