# 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/models/_core.py
# class Model(object):
#     """
#     Interface for probabilistic models of latent functions. This interface
#     includes the ability to add input/output data, evaluate the log-likelihood
#     of this data, make predictions and sample in both the latent and
#     observed space, evaluate tail probabilities, expectations, and entropy.
#     """
#     def copy(self):
#         """
#         Copy the model; this is just a convenience wrapper around deepcopy.
#         """
#         return copy.deepcopy(self)
# 
#     def add_data(self, X, Y):
#         """
#         Add input/output data `X` and `Y` to the model.
#         """
#         raise NotImplementedError
# 
#     def get_loglike(self):
#         """
#         Return the log-likelihood of the observed data.
#         """
#         raise NotImplementedError
# 
#     def sample(self, X, size=None, latent=True, rng=None):
#         """
#         Return a sample of the model at input locations `X`.
# 
#         If `size` is not given this will return an n-vector where n is the
#         length of `X`; otherwise it will return an array of shape `(size, n)`.
#         If `latent` is true the samples will be in the latent space, otherwise
#         they will be sampled in the output space.
#         """
#         raise NotImplementedError
# 
#     def predict(self, X):
#         """
#         Return mean and variance predictions `(mu, s2)` at inputs `X`.
#         """
#         raise NotImplementedError
# 
#     def get_tail(self, f, X):
#         """
#         Compute the probability that the latent function at inputs `X` exceeds
#         the target value `f`.
#         """
#         raise NotImplementedError
# 
#     def get_improvement(self, f, X):
#         """
#         Compute the expected improvement in value at inputs `X` over the target
#         value `f`.
#         """
#         raise NotImplementedError
# 
#     def get_entropy(self, X):
#         """
#         Compute the predictive entropy evaluated at inputs `X`.
#         """
#         raise NotImplementedError


import numpy as np
import scipy.special as special
import scipy.stats as stats
from ..utils.misc import rstate
from ._core import Model
        return X

    def _get_output(self, Y):
        """
        Format and verify the observed outputs.
        """
        Y = np.array(Y, dtype=int, ndmin=1)
        if np.any(np.logical_and(Y != 0, Y != 1)):
            raise ValueError('invalid outputs')
        return Y

    def _get_alphabeta(self, X=None):
        """
        Get a subset of the alpha/beta parameters, or all of them if the inputs
        X are None.
        """
        X = slice(len(self._alpha)) if (X is None) else self._get_input(X)
        return self._alpha[X], self._beta[X]

    def add_data(self, X, Y):
        X = self._get_input(X)
        Y = self._get_output(Y)
        if len(X) != len(Y):
            raise ValueError('X and Y must have the same size')
        for x, y in zip(X, Y):
            self._alpha[x] += y
            self._beta[x] += 1 - y

    def sample(self, X=None, size=None, latent=True, rng=None):
        alpha, beta = self._get_alphabeta(X)

# 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/models/_core.py
# class Model(object):
#     """
#     Interface for probabilistic models of latent functions. This interface
#     includes the ability to add input/output data, evaluate the log-likelihood
#     of this data, make predictions and sample in both the latent and
#     observed space, evaluate tail probabilities, expectations, and entropy.
#     """
#     def copy(self):
#         """
#         Copy the model; this is just a convenience wrapper around deepcopy.
#         """
#         return copy.deepcopy(self)
# 
#     def add_data(self, X, Y):
#         """
#         Add input/output data `X` and `Y` to the model.
#         """
#         raise NotImplementedError
# 
#     def get_loglike(self):
#         """
#         Return the log-likelihood of the observed data.
#         """
#         raise NotImplementedError
# 
#     def sample(self, X, size=None, latent=True, rng=None):
#         """
#         Return a sample of the model at input locations `X`.
# 
#         If `size` is not given this will return an n-vector where n is the
#         length of `X`; otherwise it will return an array of shape `(size, n)`.
#         If `latent` is true the samples will be in the latent space, otherwise
#         they will be sampled in the output space.
#         """
#         raise NotImplementedError
# 
#     def predict(self, X):
#         """
#         Return mean and variance predictions `(mu, s2)` at inputs `X`.
#         """
#         raise NotImplementedError
# 
#     def get_tail(self, f, X):
#         """
#         Compute the probability that the latent function at inputs `X` exceeds
#         the target value `f`.
#         """
#         raise NotImplementedError
# 
#     def get_improvement(self, f, X):
#         """
#         Compute the expected improvement in value at inputs `X` over the target
#         value `f`.
#         """
#         raise NotImplementedError
# 
#     def get_entropy(self, X):
#         """
#         Compute the predictive entropy evaluated at inputs `X`.
#         """
#         raise NotImplementedError


# Path: reggie/models/bandit.py
import numpy as np
import scipy.special as special
import scipy.stats as stats
from ..utils.misc import rstate
from ._core import Model

        return X

    def _get_output(self, Y):
        """
        Format and verify the observed outputs.
        """
        Y = np.array(Y, dtype=int, ndmin=1)
        if np.any(np.logical_and(Y != 0, Y != 1)):
            raise ValueError('invalid outputs')
        return Y

    def _get_alphabeta(self, X=None):
        """
        Get a subset of the alpha/beta parameters, or all of them if the inputs
        X are None.
        """
        X = slice(len(self._alpha)) if (X is None) else self._get_input(X)
        return self._alpha[X], self._beta[X]

    def add_data(self, X, Y):
        X = self._get_input(X)
        Y = self._get_output(Y)
        if len(X) != len(Y):
            raise ValueError('X and Y must have the same size')
        for x, y in zip(X, Y):
            self._alpha[x] += y
            self._beta[x] += 1 - y

    def sample(self, X=None, size=None, latent=True, rng=None):
        alpha, beta = self._get_alphabeta(X)

        rng = rstate(rng)