Beispiel #1
0
def make_k_chose_e(e_vec, k_vec):
    """
    Computes the product :math:`{\mathbf{n} \choose \mathbf{k}}`

    :param e_vec: the vector e
    :type e_vec: :class:`numpy.array`
    :param k_vec: the vector k
    :type k_vec: :class:`numpy.array`
    :return: a scalar
    """
    return product([sp.factorial(k) / (sp.factorial(e) * sp.factorial(k - e)) for e,k in zip(e_vec, k_vec)])
Beispiel #2
0
    def _make_s_pow_e(self, reac_idx, e_vec):
        """
        Compute s^e in equation 11  (see Ale et al. 2013)

        :param reac_idx: the index (that is the column in the stoichiometry matrix)
         of the reaction to consider.
        :type reac_idx: `int`
        :param e_vec: the vector e
        :return: a scalar (s^e)
        """
        return product([self.__stoichoimetry_matrix[i, reac_idx] ** e for i,e in enumerate(e_vec)])
Beispiel #3
0
def get_one_over_n_factorial(counter_entry):
    r"""
    Calculates  the :math:`\frac{1}{\mathbf{n!}}` of eq. 6 (see Ale et al. 2013).
    That is the invert of a product of factorials.
    :param counter_entry: an entry of counter. That is an array of integers of length equal to the number of variables.
    For instance, `counter_entry` could be `[1,0,1]` for three variables.
    :return: a scalar as a sympy expression
    """
    # compute all factorials
    factos = [sp.factorial(c) for c in counter_entry]
    # multiply them
    prod = product(factos)
    # return the invert
    return sp.Integer(1)/sp.S(prod)
Beispiel #4
0
    def _make_f_of_x(self, k_vec, e_vec, reaction):
        r"""
        Calculates :math:`F():math:` in eq. 12 (see Ale et al. 2013) for a specific reaction , :math:`k` and :math:`e`

        :param k_vec: the vector :math:`k`
        :param e_vec: the vector :math:`e`
        :param reaction: the equation of the reaction {:math:`a(x) in the model}
        :return: :math:`F()`
        """

        # product of all values of {x ^ (k - e)} for all combination of e and k
        prod = product([var ** (k_vec[i] - e_vec[i]) for i,var in enumerate(self.__species)])
        # multiply the product by the propensity {a(x)}
        return prod * reaction
Beispiel #5
0
    def _make_s_pow_e(self, reac_idx, e_vec):
        """
        Compute s^e in equation 11  (see Ale et al. 2013)

        :param reac_idx: the index (that is the column in the stoichiometry matrix)
         of the reaction to consider.
        :type reac_idx: `int`
        :param e_vec: the vector e
        :return: a scalar (s^e)
        """
        return product([
            self.__stoichoimetry_matrix[i, reac_idx]**e
            for i, e in enumerate(e_vec)
        ])
Beispiel #6
0
    def _gamma_factorial(self, expr, n):
        r"""
        Compute :math:`\frac {(\alpha)_m = (\alpha + m - 1)!}{(\alpha - 1)!}`
        See Eq. 3 in Gamma moment closure Lakatos 2014 unpublished

        :param expr: a symbolic expression
        :type expr:
        :param n:
        :type n: `int`

        :return: a symbolic expression
        """
        if n == 0:
            return 1
        return product([expr + i for i in range(n)])
Beispiel #7
0
    def _gamma_factorial(self, expr, n):
        r"""
        Compute :math:`\frac {(\alpha)_m = (\alpha + m - 1)!}{(\alpha - 1)!}`
        See Eq. 3 in Gamma moment closure Lakatos 2014 unpublished

        :param expr: a symbolic expression
        :type expr:
        :param n:
        :type n: `int`

        :return: a symbolic expression
        """
        if n == 0:
            return 1
        return product([expr+i for i in range(n)])
Beispiel #8
0
    def _make_f_of_x(self, k_vec, e_vec, reaction):
        r"""
        Calculates :math:`F():math:` in eq. 12 (see Ale et al. 2013) for a specific reaction , :math:`k` and :math:`e`

        :param k_vec: the vector :math:`k`
        :param e_vec: the vector :math:`e`
        :param reaction: the equation of the reaction {:math:`a(x) in the model}
        :return: :math:`F()`
        """

        # product of all values of {x ^ (k - e)} for all combination of e and k
        prod = product([
            var**(k_vec[i] - e_vec[i]) for i, var in enumerate(self.__species)
        ])
        # multiply the product by the propensity {a(x)}
        return prod * reaction
Beispiel #9
0
    def _compute_one_moment(self, all_trajectories, mean_trajectories, moment):

        # the expectation of the product:
        #products_of_sps = [product(trajs) for trajs in all_trajectories]
        n_vec = moment.n_vector

        to_multipl = []

        for i, trajs in enumerate(zip(*all_trajectories)):
            mean_of_sp = mean_trajectories[i]
            order_of_sp = n_vec[i]
            xi_minus_ex = [(t - mean_of_sp) ** order_of_sp for t in trajs]
            for x in xi_minus_ex:
                x.set_description(moment)
            to_multipl.append(xi_minus_ex)

        to_sum = [product(xs) for xs in zip(*to_multipl)]

        return sum(to_sum)/ float(len(to_sum))
Beispiel #10
0
    def _compute_one_closed_central_moment(self, moment, covariance_matrix):
        r"""
        Compute each row of closed central moment based on Isserlis' Theorem of calculating higher order moments
        of multivariate normal distribution in terms of covariance matrix

        :param moment: moment matrix
        :param covariance_matrix: matrix containing variances and covariances
        :return: each row of closed central moment
        """

        # If moment order is odd, higher order moments equals 0
        if moment.order % 2 != 0:
            return sp.Integer(0)

        # index of species
        idx = [i for i in range(len(moment.n_vector))]

        # repeat the index of a species as many time as its value in counter
        list_for_partition = reduce(
            operator.add, map(lambda i, c: [i] * c, idx, moment.n_vector))

        # If moment order is even, :math: '\mathbb{E} [x_1x_2 \ldots  x_2_n] = \sum \prod\mathbb{E} [x_ix_j] '
        # e.g.:math: '\mathbb{E} [x_1x_2x_3x_4] = \mathbb{E} [x_1x_2] +\mathbb{E} [x_1x_3] +\mathbb{E} [x_1x_4]
        # +\mathbb{E} [x_2x_3]+\mathbb{E} [x_2x_4]+\mathbb{E} [x_3x_4]'
        # For second order moment, there is only one way of partitioning. Hence, no need to generate partitions
        if moment.order == 2:
            return covariance_matrix[list_for_partition[0],
                                     list_for_partition[1]]

        # For even moment order other than 2, generate a list of partitions of the indices of covariances
        else:
            each_row = []
            for idx_pair in self._generate_partitions(list_for_partition):
                # Retrieve the pairs of covariances using the pairs of partitioned indices
                l = [covariance_matrix[i, j] for i, j in idx_pair]
                # Calculate the product of each pair of covariances
                each_row.append(product(l))

            # The corresponding closed central moment of that moment order is the sum of the products
            return sum(each_row)
Beispiel #11
0
    def _compute_one_closed_central_moment(self, moment, covariance_matrix):
        r"""
        Compute each row of closed central moment based on Isserlis' Theorem of calculating higher order moments
        of multivariate normal distribution in terms of covariance matrix

        :param moment: moment matrix
        :param covariance_matrix: matrix containing variances and covariances
        :return: each row of closed central moment
        """

        # If moment order is odd, higher order moments equals 0
        if moment.order % 2 != 0:
            return sp.Integer(0)

        # index of species
        idx = [i for i in range(len(moment.n_vector))]

        # repeat the index of a species as many time as its value in counter
        list_for_partition = reduce(operator.add, map(lambda i, c: [i] * c, idx, moment.n_vector))

        # If moment order is even, :math: '\mathbb{E} [x_1x_2 \ldots  x_2_n] = \sum \prod\mathbb{E} [x_ix_j] '
        # e.g.:math: '\mathbb{E} [x_1x_2x_3x_4] = \mathbb{E} [x_1x_2] +\mathbb{E} [x_1x_3] +\mathbb{E} [x_1x_4]
        # +\mathbb{E} [x_2x_3]+\mathbb{E} [x_2x_4]+\mathbb{E} [x_3x_4]'
        # For second order moment, there is only one way of partitioning. Hence, no need to generate partitions
        if moment.order == 2:
            return covariance_matrix[list_for_partition[0], list_for_partition[1]]

        # For even moment order other than 2, generate a list of partitions of the indices of covariances
        else:
            each_row = []
            for idx_pair in self._generate_partitions(list_for_partition):
                # Retrieve the pairs of covariances using the pairs of partitioned indices
                l = [covariance_matrix[i, j] for i,j in idx_pair]
                # Calculate the product of each pair of covariances
                each_row.append(product(l))

            # The corresponding closed central moment of that moment order is the sum of the products
            return sum(each_row)
Beispiel #12
0
def eq_central_moments(n_counter, k_counter, dmu_over_dt, species, propensities, stoichiometry_matrix, max_order):
    r"""
    Function used to calculate the terms required for use in equations giving the time dependence of central moments.

    The function returns the list Containing the sum of the following terms in in equation 9,
    for each of the :math:`[n_1, ..., n_d]` combinations in eq. 9 where ... is ... # FIXME

    .. math::
        \mathbf{ {n \choose k} } (-1)^{ \mathbf{n-k} }
        [ \alpha \frac{d\beta}{dt} + \beta \frac{d\alpha}{dt} ]


    :param n_counter: a list of :class:`~means.core.descriptors.Moment`\s representing central moments
    :type n_counter: list[:class:`~means.core.descriptors.Moment`]
    :param k_counter: a list of :class:`~means.core.descriptors.Moment`\s representing raw moments
    :type k_counter: list[:class:`~means.core.descriptors.Moment`]
    :param dmu_over_dt: du/dt in paper
    :param species: species matrix: y_0, y_1,..., y_d
    :param propensities: propensities matrix
    :param stoichiometry_matrix: stoichiometry matrix
    :return: central_moments matrix with `(len(n_counter)-1)` rows and one column per each :math:`[n_1, ... n_d]` combination
    """
    central_moments = []


    # Loops through required combinations of moments (n1,...,nd)
    # (does not include 0th order central moment as this is 1,
    # or 1st order central moment as this is 0

    # copy dmu_mat matrix as a list of rows vectors (1/species)
    dmu_mat = [sp.Matrix(l).T for l in dmu_over_dt.tolist()]

    d_beta_over_dt_calculator = DBetaOverDtCalculator(propensities,n_counter,stoichiometry_matrix, species)

    for n_iter in n_counter:
        # skip zeroth moment
        if n_iter.order == 0 or n_iter.order > max_order:
            continue

        n_vec = n_iter.n_vector

        # Find all moments in k_counter that are lower than the current n_iter
        k_lower = [k for k in k_counter if n_iter >= k]

        taylor_exp_mat = []

        for k_iter in k_lower:
            k_vec = k_iter.n_vector

            # (n k) binomial term in equation 9
            n_choose_k = make_k_chose_e(k_vec, n_vec)

            # (-1)^(n-k) term in equation 9
            minus_one_pow_n_minus_k = product([sp.Integer(-1) ** (n - m) for (n,m)
                                               in zip(n_vec, k_vec)])

            # Calculate alpha, dalpha_over_dt terms in equation 9
            alpha = product([s ** (n - k) for s, n, k in zip(species, n_vec, k_vec)])
            # eq 10 {(n - k) mu_i^(-1)} corresponds to {(n - k)/s}. s is symbol for mean of a species

            # multiplies by alpha an the ith row of dmu_mat and sum it to get dalpha_over_dt
            # eq 10 {(n - k) mu_i^(-1)} corresponds to {(n - k)/s}
            dalpha_over_dt = sympy_sum_list([((n - k) / s) * alpha * mu_row for s, n, k, mu_row
                                             in zip(species, n_vec, k_vec, dmu_mat)])

            # e_counter contains elements of k_counter lower than the current k_iter
            e_counter = [k for k in k_counter if k_iter >= k and k.order > 0]

            dbeta_over_dt = d_beta_over_dt_calculator.get(k_iter.n_vector, e_counter)

            # Calculate beta, dbeta_over_dt terms in equation 9
            if len(e_counter) == 0:
                beta = 1
            else:
                beta = k_iter.symbol

            taylor_exp_mat.append(n_choose_k * minus_one_pow_n_minus_k * (alpha * dbeta_over_dt + beta * dalpha_over_dt))

        # Taylorexp is a matrix which has an entry equal to
        # the `n_choose_k * minus_one_pow_n_minus_k * (AdB/dt + beta dA/dt)` term in equation 9  for each k1,..,kd
        # These are summed over to give the Taylor Expansion for each n1,..,nd combination in equation 9
        central_moments.append(sum_of_cols(sp.Matrix(taylor_exp_mat)))

    return sp.Matrix(central_moments)
Beispiel #13
0
    def _get_parameter_symbols(self, n_counter, k_counter):
        r"""
        Calculates parameters Y expressions and beta coefficients in
        :math:`X = {A(\beta_0,\beta_1\ldots \beta_n) \cdot Y}`

        :param n_counter: a list of :class:`~means.core.descriptors.Moment`\s representing central moments
        :type n_counter: list[:class:`~means.core.descriptors.Moment`]
        :param k_counter: a list of :class:`~means.core.descriptors.Moment`\s representing raw moments
        :type k_counter: list[:class:`~means.core.descriptors.Moment`]
        :return: two column matrices Y expressions and beta multipliers
        """

        n_moment = self.max_order + 1

        expectation_symbols = sp.Matrix(
            [n.symbol for n in k_counter if n.order == 1])

        n_species = len(expectation_symbols)

        # Create auxiliary symbolic species Y_{ij}, for i,j = 0 ... (n-1) and mirror, so that Y_{ij}=Y_{ji}
        symbolic_species = sp.Matrix([[
            sp.Symbol(('Y_{0}'.format(str(j))) + '{0}'.format(str(i)))
            for i in range(n_species)
        ] for j in range(n_species)])
        for i in range(n_species):
            for j in range(i + 1, n_species):
                symbolic_species[j, i] = symbolic_species[i, j]

        # Obtain beta terms explaining how original variables are derived from auxiliary ones
        if self.is_multivariate:
            # :math: `X_i = \sum_j Y_{ij}`
            beta_in_matrix = sp.Matrix(
                [sum(symbolic_species[i, :]) for i in range(n_species)])
        else:
            # In univariate case, only the diagonal elements are needed
            beta_in_matrix = sp.Matrix(
                [symbolic_species[i, i] for i in range(n_species)])

        # Covariance symbols are read into a matrix. Variances are the diagonal elements
        covariance_matrix = sp.Matrix(
            n_species, n_species,
            lambda x, y: self._get_covariance_symbol(n_counter, x, y))
        variance_symbols = sp.Matrix(
            [covariance_matrix[i, i] for i in range(n_species)])

        # Compute :math:  `\beta_i = Var(X_i)/\mathbb{E}(X_i) \bar\alpha_i = \mathbb{E}(X_i)^2/Var(X_i)`
        beta_exprs = sp.Matrix(
            [v / e for e, v in zip(expectation_symbols, variance_symbols)])
        alpha_bar_exprs = sp.Matrix([
            (e**2) / v for e, v in zip(expectation_symbols, variance_symbols)
        ])

        if self.is_multivariate:
            # Calculate nondiagonal elements from covariances
            alpha_exprs = sp.Matrix(
                n_species, n_species, lambda i, j: covariance_matrix[i, j] /
                (beta_exprs[i] * beta_exprs[j]))
        else:
            # Covariances are zero in univariate case
            alpha_exprs = sp.Matrix(n_species, n_species, lambda i, j: 0)
        for sp_idx in range(n_species):
            # Compute diagonal elements as :math: `\alpha_{ii} = \bar\alpha_{i} - \sum(\alpha_{ij})` //equiv to \bar\alpha_{i} in univariate
            alpha_exprs[sp_idx, sp_idx] = 0
            alpha_exprs[sp_idx, sp_idx] = alpha_bar_exprs[sp_idx] - sum(
                alpha_exprs[sp_idx, :])

        # Each row in moment matrix contains the exponents of Xs for a given moment
        # Each row in Y_exprs and beta_multipliers has elements on the appropriate power
        # determined by the corresponding row in the moment matrix
        Y_exprs = []
        beta_multipliers = []

        positive_n_counter = [n for n in n_counter if n.order > 0]
        for mom in positive_n_counter:
            Y_exprs.append(
                product([(b**s).expand()
                         for b, s in zip(beta_in_matrix, mom.n_vector)]))
            beta_multipliers.append(
                product([(b**s).expand()
                         for b, s in zip(beta_exprs, mom.n_vector)]))

        Y_exprs = sp.Matrix(Y_exprs).applyfunc(sp.expand)
        beta_multipliers = sp.Matrix(beta_multipliers)

        # Substitute alpha expressions in place of symbolic species Ys
        # by going through all powers up to the moment order for closure
        subs_pairs = []
        for i, a in enumerate(alpha_exprs):
            Y_to_substitute = [
                symbolic_species[i]**n for n in range(2, n_moment + 1)
            ]

            # Obtain alpha term for higher order moments :math: `\mathbb{E}(Y_{ij}^n) \rightarrow (\alpha_{ij})_n`
            alpha_m = [
                self._gamma_factorial(a, n) for n in range(2, n_moment + 1)
            ]

            # Substitute alpha term for symbolic species
            subs_pairs += zip(Y_to_substitute, alpha_m)
            subs_pairs.append((symbolic_species[i],
                               a))  # Add first order expression to the end
        Y_exprs = substitute_all(Y_exprs, subs_pairs)

        return Y_exprs, beta_multipliers
Beispiel #14
0
    def _get_parameter_symbols(self, n_counter, k_counter):
        r"""
        Calculates parameters Y expressions and beta coefficients in
        :math:`X = {A(\beta_0,\beta_1\ldots \beta_n) \cdot Y}`

        :param n_counter: a list of :class:`~means.core.descriptors.Moment`\s representing central moments
        :type n_counter: list[:class:`~means.core.descriptors.Moment`]
        :param k_counter: a list of :class:`~means.core.descriptors.Moment`\s representing raw moments
        :type k_counter: list[:class:`~means.core.descriptors.Moment`]
        :return: two column matrices Y expressions and beta multipliers
        """

        n_moment = self.max_order + 1

        expectation_symbols = sp.Matrix([n.symbol for n in k_counter if n.order == 1])


        n_species = len(expectation_symbols)

        # Create auxiliary symbolic species Y_{ij}, for i,j = 0 ... (n-1) and mirror, so that Y_{ij}=Y_{ji}
        symbolic_species=sp.Matrix([[sp.Symbol(('Y_{0}'.format(str(j)))+'{0}'.format(str(i))) for i in range(n_species)]for j in range(n_species)])
        for i in range(n_species):
            for j in range(i+1,n_species):
                symbolic_species[j,i]=symbolic_species[i,j]


        # Obtain beta terms explaining how original variables are derived from auxiliary ones
        if self.is_multivariate:
            # :math: `X_i = \sum_j Y_{ij}`
            beta_in_matrix = sp.Matrix([sum(symbolic_species[i,:]) for i in range(n_species)])
        else :
            # In univariate case, only the diagonal elements are needed
            beta_in_matrix = sp.Matrix([symbolic_species[i,i] for i in range(n_species)])

        # Covariance symbols are read into a matrix. Variances are the diagonal elements
        covariance_matrix = sp.Matrix(n_species,n_species, lambda x,y: self._get_covariance_symbol(n_counter,x,y))
        variance_symbols = sp.Matrix([covariance_matrix[i,i] for i in range(n_species)])


        # Compute :math:  `\beta_i = Var(X_i)/\mathbb{E}(X_i) \bar\alpha_i = \mathbb{E}(X_i)^2/Var(X_i)`
        beta_exprs = sp.Matrix([v / e for e,v in zip(expectation_symbols,variance_symbols)])
        alpha_bar_exprs = sp.Matrix([(e ** 2) / v for e,v in zip(expectation_symbols,variance_symbols)])

        if self.is_multivariate:
            # Calculate nondiagonal elements from covariances
            alpha_exprs = sp.Matrix(n_species,n_species, lambda i,j: covariance_matrix[i,j]/(beta_exprs[i]*beta_exprs[j]))
        else:
            # Covariances are zero in univariate case
            alpha_exprs = sp.Matrix(n_species,n_species, lambda i,j: 0)
        for sp_idx in range(n_species):
            # Compute diagonal elements as :math: `\alpha_{ii} = \bar\alpha_{i} - \sum(\alpha_{ij})` //equiv to \bar\alpha_{i} in univariate
            alpha_exprs[sp_idx,sp_idx]=0
            alpha_exprs[sp_idx,sp_idx]=alpha_bar_exprs[sp_idx]-sum(alpha_exprs[sp_idx,:])


        # Each row in moment matrix contains the exponents of Xs for a given moment
        # Each row in Y_exprs and beta_multipliers has elements on the appropriate power
        # determined by the corresponding row in the moment matrix
        Y_exprs = []
        beta_multipliers = []

        positive_n_counter = [n for n in n_counter if n.order > 0]
        for mom in positive_n_counter:
            Y_exprs.append(product([(b ** s).expand() for b, s in zip(beta_in_matrix, mom.n_vector)]))
            beta_multipliers.append(product([(b ** s).expand() for b, s in zip(beta_exprs, mom.n_vector)]))

        Y_exprs = sp.Matrix(Y_exprs).applyfunc(sp.expand)
        beta_multipliers = sp.Matrix(beta_multipliers)

        # Substitute alpha expressions in place of symbolic species Ys
        # by going through all powers up to the moment order for closure
        subs_pairs = []
        for i,a in enumerate(alpha_exprs):
            Y_to_substitute = [symbolic_species[i]**n for n in range(2, n_moment+1)]

            # Obtain alpha term for higher order moments :math: `\mathbb{E}(Y_{ij}^n) \rightarrow (\alpha_{ij})_n`
            alpha_m = [self._gamma_factorial(a,n) for n in range(2, n_moment+1)]

            # Substitute alpha term for symbolic species
            subs_pairs += zip(Y_to_substitute, alpha_m)
            subs_pairs.append((symbolic_species[i], a)) # Add first order expression to the end
        Y_exprs = substitute_all(Y_exprs, subs_pairs)

        return Y_exprs, beta_multipliers