<commit_before>################################################################################
# Copyright (C) 2011-2012,2014 <NAME>
#
# This file is licensed under the MIT License.
################################################################################


"""
Module for the gamma distribution node.
"""

import numpy as np
import scipy.special as special

from .node import Node
from .deterministic import Deterministic
from .stochastic import Stochastic
from .expfamily import ExponentialFamily, ExponentialFamilyDistribution
from .constant import Constant
from .node import Moments
from .wishart import WishartMoments

from bayespy.utils import misc


def diagonal(alpha):
    """
    Create a diagonal Wishart node from a Gamma node.
    """
    return _GammaToDiagonalWishart(alpha,
                                   name=alpha.name + " as Wishart")


class GammaPriorMoments(Moments):
    """
    Class for the moments of the shape parameter in gamma distributions.
    """
    
    
    def compute_fixed_moments(self, a):
        """
        Compute the moments for a fixed value
        """
        u0 = a
        u1 = special.gammaln(a)
        return [u0, u1]
    

    def compute_dims_from_values(self, a):
        """
        Return the shape of the moments for a fixed value.
        """
        return ( (), () )
    

class GammaMoments(Moments):
    """
    Class for the moments of gamma variables.
    """
    
    
    def compute_fixed_moments(self, x):
        """
        Compute the moments for a fixed value
        """
        if np.any(x < 0):
            raise ValueError("Values must be positive")
        u0 = x
        u1 = np.log(x)
        return [u0, u1]


    def compute_dims_from_values(self, x):
        """
        Return the shape of the moments for a fixed value.
        """
        return ( (), () )
    

class GammaDistribution(ExponentialFamilyDistribution):
    """
    Class for the VMP formulas of gamma variables.
    """    
    

    def compute_message_to_parent(self, parent, index, u_self, u_a, u_b):
        r"""
        Compute the message to a parent node.
        """
        x = u_self[0]
        logx = u_self[1]

        if index == 0:
            b = u_b[0]
            logb = u_b[1]
            return [logx + logb,
                    -1]
        elif index == 1:
            a = u_a[0]
            return [-x,
                    a]
        else:
            raise ValueError("Index out of bounds")


    def compute_phi_from_parents(self, *u_parents, mask=True):
        r"""
        Compute the natural parameter vector given parent moments.
        """
        return [-u_parents[1][0],
                1*u_parents[0][0]]
    

    def compute_moments_and_cgf(self, phi, mask=True):
        r"""
        Compute the moments and :math:`g(\phi)`.

        .. math::

           \overline{\mathbf{u}}  (\boldsymbol{\phi})
           &=
           \begin{bmatrix}
             - \frac{\phi_2} {\phi_1}
             \\
             \psi(\phi_2) - \log(-\phi_1)
           \end{bmatrix}
           \\
           g_{\boldsymbol{\phi}} (\boldsymbol{\phi})
           &=
           TODO
        """
        with np.errstate(invalid='raise', divide='raise'):
            log_b = np.log(-phi[0])
            u0 = phi[1] / (-phi[0])
        u1 = special.digamma(phi[1]) - log_b
        u = [u0, u1]
        g = phi[1] * log_b - special.gammaln(phi[1])
        return (u, g)


    def compute_cgf_from_parents(self, *u_parents):
        r"""
        Compute :math:`\mathrm{E}_{q(p)}[g(p)]`
        """
        a = u_parents[0][0]
        gammaln_a = u_parents[0][1] #special.gammaln(a)
        b = u_parents[1][0]
        log_b = u_parents[1][1]
        g = a * log_b - gammaln_a
        return g

            
    def compute_fixed_moments_and_f(self, x, mask=True):
        r"""
        Compute the moments and :math:`f(x)` for a fixed value.
        """
        if np.any(x < 0):
            raise ValueError("Values must be positive")
        logx = np.log(x)
        u = [x, logx]
        f = -logx
        return (u, f)


    def random(self, *phi, plates=None):
        r"""
        Draw a random sample from the distribution.
        """
        return np.random.gamma(phi[1],
                               -1/phi[0],
                               size=plates)

    
    def compute_gradient(self, g, u, phi):
        r"""
        Compute the moments and :math:`g(\phi)`.

        .. math::

           \mathrm{d}\overline{\mathbf{u}} &=
           \begin{bmatrix}
             - \frac{\mathrm{d}\phi_2} {phi_1} + \frac{\phi_2}{\phi_1^2} \mathrm{d}\phi_1
             \\
             \psi^{(1)}(\phi_2) \mathrm{d}\phi_2 - \frac{1}{\phi_1} \mathrm{d}\phi_1
           \end{bmatrix}
<commit_msg>BUG: Accept lists as gamma observations<commit_after>################################################################################
# Copyright (C) 2011-2012,2014 <NAME>
#
# This file is licensed under the MIT License.
################################################################################


"""
Module for the gamma distribution node.
"""

import numpy as np
import scipy.special as special

from .node import Node
from .deterministic import Deterministic
from .stochastic import Stochastic
from .expfamily import ExponentialFamily, ExponentialFamilyDistribution
from .constant import Constant
from .node import Moments
from .wishart import WishartMoments

from bayespy.utils import misc


def diagonal(alpha):
    """
    Create a diagonal Wishart node from a Gamma node.
    """
    return _GammaToDiagonalWishart(alpha,
                                   name=alpha.name + " as Wishart")


class GammaPriorMoments(Moments):
    """
    Class for the moments of the shape parameter in gamma distributions.
    """
    
    
    def compute_fixed_moments(self, a):
        """
        Compute the moments for a fixed value
        """
        u0 = a
        u1 = special.gammaln(a)
        return [u0, u1]
    

    def compute_dims_from_values(self, a):
        """
        Return the shape of the moments for a fixed value.
        """
        return ( (), () )
    

class GammaMoments(Moments):
    """
    Class for the moments of gamma variables.
    """
    
    
    def compute_fixed_moments(self, x):
        """
        Compute the moments for a fixed value
        """
        if np.any(x < 0):
            raise ValueError("Values must be positive")
        u0 = x
        u1 = np.log(x)
        return [u0, u1]


    def compute_dims_from_values(self, x):
        """
        Return the shape of the moments for a fixed value.
        """
        return ( (), () )
    

class GammaDistribution(ExponentialFamilyDistribution):
    """
    Class for the VMP formulas of gamma variables.
    """    
    

    def compute_message_to_parent(self, parent, index, u_self, u_a, u_b):
        r"""
        Compute the message to a parent node.
        """
        x = u_self[0]
        logx = u_self[1]

        if index == 0:
            b = u_b[0]
            logb = u_b[1]
            return [logx + logb,
                    -1]
        elif index == 1:
            a = u_a[0]
            return [-x,
                    a]
        else:
            raise ValueError("Index out of bounds")


    def compute_phi_from_parents(self, *u_parents, mask=True):
        r"""
        Compute the natural parameter vector given parent moments.
        """
        return [-u_parents[1][0],
                1*u_parents[0][0]]
    

    def compute_moments_and_cgf(self, phi, mask=True):
        r"""
        Compute the moments and :math:`g(\phi)`.

        .. math::

           \overline{\mathbf{u}}  (\boldsymbol{\phi})
           &=
           \begin{bmatrix}
             - \frac{\phi_2} {\phi_1}
             \\
             \psi(\phi_2) - \log(-\phi_1)
           \end{bmatrix}
           \\
           g_{\boldsymbol{\phi}} (\boldsymbol{\phi})
           &=
           TODO
        """
        with np.errstate(invalid='raise', divide='raise'):
            log_b = np.log(-phi[0])
            u0 = phi[1] / (-phi[0])
        u1 = special.digamma(phi[1]) - log_b
        u = [u0, u1]
        g = phi[1] * log_b - special.gammaln(phi[1])
        return (u, g)


    def compute_cgf_from_parents(self, *u_parents):
        r"""
        Compute :math:`\mathrm{E}_{q(p)}[g(p)]`
        """
        a = u_parents[0][0]
        gammaln_a = u_parents[0][1] #special.gammaln(a)
        b = u_parents[1][0]
        log_b = u_parents[1][1]
        g = a * log_b - gammaln_a
        return g


    def compute_fixed_moments_and_f(self, x, mask=True):
        r"""
        Compute the moments and :math:`f(x)` for a fixed value.
        """
        x = np.asanyarray(x)
        if np.any(x < 0):
            raise ValueError("Values must be positive")
        logx = np.log(x)
        u = [x, logx]
        f = -logx
        return (u, f)


    def random(self, *phi, plates=None):
        r"""
        Draw a random sample from the distribution.
        """
        return np.random.gamma(phi[1],
                               -1/phi[0],
                               size=plates)

    
    def compute_gradient(self, g, u, phi):
        r"""
        Compute the moments and :math:`g(\phi)`.

        .. math::

           \mathrm{d}\overline{\mathbf{u}} &=
           \begin{bmatrix}
             - \frac{\mathrm{d}\phi_2} {phi_1} + \frac{\phi_2}{\phi_1^2} \mathrm{d}\phi_1
             \\
             \psi^{(1)}(\phi_2) \mathrm{d}\phi_2 - \frac{1}{\phi_1} \mathrm{d}\phi_1
           \end{bmatrix}

{'fraction_non_alphanumeric': 0.15388628064684404, 'fraction_numerical': 0.015023474178403756, 'mean_word_length': 1.7263936291240045, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7041379', 'n_tokens_mistral': 3061, 'n_tokens_neox': 2906, 'n_words': 753}