jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def apply(self, pc, x, y):
        X = dlpack.from_dlpack(x.toDLPack(mode="r")).reshape(self._m, self._n)
        Y = dlpack.from_dlpack(y).reshape(self._m, self._n)
        LU, pivots = self.get_factor()
        torch.linalg.lu_solve(LU, pivots, X, out=Y, left=False)
//  [python]
def applyTranspose(self, pc, x, y):
        X = dlpack.from_dlpack(x.toDLPack(mode="r")).reshape(self._m, self._n)
        Y = dlpack.from_dlpack(y).reshape(self._m, self._n)
        LU, pivots = self.get_factor()
        torch.solve(X, LU, out=Y, transposed=True)
//  [python]
def applyTranspose(self, pc, x, y):
        X = dlpack.from_dlpack(x.toDLPack(mode="r")).reshape(self._m, self._n)
        Y = dlpack.from_dlpack(y).reshape(self._m, self._n)
        LU, pivots = self.get_factor()
        torch.linalg.lu_solve(LU, pivots, X, out=Y, adjoint=True, left=False)
//  [python]
def btrisolve(b, LU_data, LU_pivots, out=None):
    r"""Solves the system of equations :math:`Ax = b` using the partially pivoted LU
    factorization of :math:`A` given by :attr:`LU_data` and :attr:`LU_pivots`.

    For more information regarding :func:`torch.btrisolve`, please check
    :func:`torch.lu_solve`.

    .. warning::
        :func:`torch.btrisolve` is deprecated in favour of :func:`torch.lu_solve` and will be
        removed in the next release. Please use :func:`torch.lu_solve` instead.
    """
    warnings.warn("torch.btrisolve is deprecated in favour of torch.lu_solve and will be "
                  "removed in the next release. Please use torch.lu_solve instead.", stacklevel=2)
    return torch.lu_solve(b, LU_data=LU_data, LU_pivots=LU_pivots, out=out)
//  [python]
def btrisolve(b, LU_data, LU_pivots, out=None):
    r"""Solves the system of equations :math:`Ax = b` using the partially pivoted LU
    factorization of :math:`A` given by :attr:`LU_data` and :attr:`LU_pivots`.

    For more information regarding :func:`torch.btrisolve`, please check
    :func:`torch.lu_solve`.

    .. warning::
        :func:`torch.btrisolve` is deprecated in favour of :func:`torch.lu_solve` and will be
        removed in the next release. Please use :func:`torch.lu_solve` instead.
    """
    warnings.warn("torch.btrisolve is deprecated in favour of torch.lu_solve and will be "
                  "removed in the next release. Please use torch.lu_solve instead.", stacklevel=2)
    return torch.linalg.lu_solve(b, LU_data, LU_pivots, out=out)
//  [python]
def _inverse_given_params(self, inputs, conditional_params):
        lower, upper = self._create_lower_upper(
            conditional_params
        )
        outputs = torch.solve(torch.broadcast_to(self.default_pivot, inputs.shape),
                                        torch.tril(lower, -1) + upper,
                                        inputs.unsqueeze(-1))[0]

        logabsdet = -upper.diagonal(0, -1, -2).log().sum(-1)  # ...#inputs.new_ones(inputs.shape[0])
        return outputs.view(inputs.shape), logabsdet
//  [python]
def _inverse_given_params(self, inputs, conditional_params):
        lower, upper = self._create_lower_upper(
            conditional_params
        )
        outputs = torch.linalg.lu_solve(torch.tril(lower, -1) + upper,
                                        torch.broadcast_to(self.default_pivot, inputs.shape),
                                        inputs.unsqueeze(-1))

        logabsdet = -upper.diagonal(0, -1, -2).log().sum(-1)  # ...#inputs.new_ones(inputs.shape[0])
        return outputs.view(inputs.shape), logabsdet
//  [python]
def forward(ctx, A, b, LU=None, P=None):
        """
        Forward solving
        """
        if LU is None or P is None:
            with torch.no_grad():
                LU, P = torch.linalg.lu_factor(A)

        x = torch.solve(b, torch.triangular_solve(P @ b, LU, upper=False)[0])

        # --- save for backwards:
        ctx.save_for_backward(LU, P, x)

        return x
//  [python]
def forward(ctx, A, b, LU=None, P=None):
        """
        Forward solving
        """
        if LU is None or P is None:
            with torch.no_grad():
                LU, P = torch.linalg.lu_factor(A)

        x = torch.linalg.lu_solve(LU, P, b)

        # --- save for backwards:
        ctx.save_for_backward(LU, P, x)

        return x
//  [python]
def backward(ctx, dl_dx):
        """
        Fixed point backward differentiation. Note this only works for symmetric A.
        """
        LU, P, x = ctx.saved_tensors

        # --- backward solve:
        if len(x.shape) < 3:
            xt = x.transpose
        else:
            xt = torch.transpose(x, 1, 2)
        dx = torch.solve(P @ -dl_dx, LU)[0]
        dl_dA = torch.matmul(dx, xt)
        dl_db = -dx

        grads = (dl_dA, dl_db, None, None)

        return grads
//  [python]
def backward(ctx, dl_dx):
        """
        Fixed point backward differentiation. Note this only works for symmetric A.
        """
        LU, P, x = ctx.saved_tensors

        # --- backward solve:
        if len(x.shape) < 3:
            xt = x.transpose
        else:
            xt = torch.transpose(x, 1, 2)
        dx = torch.linalg.lu_solve(LU, P, -dl_dx)
        dl_dA = torch.matmul(dx, xt)
        dl_db = -dx

        grads = (dl_dA, dl_db, None, None)

        return grads
//  [python]
def thomas_solve(lu, pivots, B, v):
    """Simple function implementing a Thomas solve

    Solves in place of v

    Args:
        lu (torch.tensor): factorized diagonal blocks, (nblk,sbat,sblk,sblk)
        pivots (torch.tensor): pivots for factorization
        B (torch.tensor): lower diagonal blocks (nblk-1,sbat,sblk,sblk)
        v (torch.tensor): right hand side (nblk,sbat,sblk)
    """
    i = 0
    v[i] = torch.solve(v[i], torch.lu_unpack(lu[i], pivots[i]))[0]
    for i in range(1, lu.shape[0]):
        v[i] = torch.solve(v[i] - torch.bmm(B[i - 1], v[i - 1].clone()), torch.lu_unpack(lu[i], pivots[i]))[0]

    return v
//  [python]
def thomas_solve(lu, pivots, B, v):
    """Simple function implementing a Thomas solve

    Solves in place of v

    Args:
        lu (torch.tensor): factorized diagonal blocks, (nblk,sbat,sblk,sblk)
        pivots (torch.tensor): pivots for factorization
        B (torch.tensor): lower diagonal blocks (nblk-1,sbat,sblk,sblk)
        v (torch.tensor): right hand side (nblk,sbat,sblk)
    """
    i = 0
    v[i] = torch.linalg.lu_solve(lu[i], pivots[i], v[i])
    for i in range(1, lu.shape[0]):
        v[i] = torch.linalg.lu_solve(
            lu[i], pivots[i], v[i] - torch.bmm(B[i - 1], v[i - 1].clone())
        )

    return v
//  [python]
def matvec(self, v):
        """
        Complete the backsolve for a given right hand side

        Args:
            v (torch.tensor): tensor of shape (nblk, sbat, sblk, 1)
        """
        # We could do this in place if it wasn't for the pad
        self.B = pad(self.B, (0, 0, 0, 0, 0, 0, 1, 0))

        # Now figure out how many powers of 2 we need to complete our matrix
        for s, e in zip(*self._pow2(self.nblk)):
            self.B[s + 1 : e], v[s + 1 : e] = self._solve_block(
                self.lu[s:e], self.pivots[s:e], self.B[s:e], v[s:e]
            )

        # To retain consistent sizes
        self.B = self.B[1:]

        return torch.solve(v, torch.lu_unpack(self.lu, self.pivots))
//  [python]
def matvec(self, v):
        """
        Complete the backsolve for a given right hand side

        Args:
            v (torch.tensor): tensor of shape (nblk, sbat, sblk, 1)
        """
        # We could do this in place if it wasn't for the pad
        self.B = pad(self.B, (0, 0, 0, 0, 0, 0, 1, 0))

        # Now figure out how many powers of 2 we need to complete our matrix
        for s, e in zip(*self._pow2(self.nblk)):
            self.B[s + 1 : e], v[s + 1 : e] = self._solve_block(
                self.lu[s:e], self.pivots[s:e], self.B[s:e], v[s:e]
            )

        # To retain consistent sizes
        self.B = self.B[1:]

        return torch.linalg.lu_solve(self.lu, self.pivots, v)
//  [python]
def _solve_block(self, lu, pivots, B, v):
        """Solve a subsection of the matrix via PCR

        Args:
            lu (torch.tensor): (ncurr,sbat,sblk,sblk)
            pivots (torch.tensor): (ncurr,sbat,sblk)
            B (torch.tensor): (ncurr,sbat,sblk,sblk)
            v (torch.tensor): (ncurr,sbat,sblk,1)
        """
        # Number of iterations required to reduce this block
        niter = lu.shape[0].bit_length() - 1

        # Add the extra working dimension to the start of everything
        lu = lu.unsqueeze(0)
        pivots = pivots.unsqueeze(0)
        B = B.unsqueeze(0)
        v = v.unsqueeze(0)

        # Actually start reduction!
        for i in range(niter):
            # Reduce RHS
            v[:, 1:] -= mbmm(
                B[:, 1:], torch.solve(v[:, :-1], torch.lu_unpack(*torch.lu(lu[:, :-1]), pivots[:, :-1]))[0]
            )

            # Reduce off diagonal coefficients
            B[:, 2:] = -mbmm(
                B[:, 2:],
                torch.solve(B[:, 1:-1], torch.lu_unpack(*torch.lu(lu[:, 1:-1]), pivots[:, 1:-1]))[0],
            )

            # Shuffle dimensions
            v = self._cyclic_shift(v, i)
            B = self._cyclic_shift(B, i)
            lu = self._cyclic_shift(lu, i)
            pivots = self._cyclic_shift(pivots, i)

        return B.squeeze(1)[1:], v.squeeze(1)[1:]
//  [python]
def _solve_block(self, lu, pivots, B, v):
        """Solve a subsection of the matrix via PCR

        Args:
            lu (torch.tensor): (ncurr,sbat,sblk,sblk)
            pivots (torch.tensor): (ncurr,sbat,sblk)
            B (torch.tensor): (ncurr,sbat,sblk,sblk)
            v (torch.tensor): (ncurr,sbat,sblk,1)
        """
        # Number of iterations required to reduce this block
        niter = lu.shape[0].bit_length() - 1

        # Add the extra working dimension to the start of everything
        lu = lu.unsqueeze(0)
        pivots = pivots.unsqueeze(0)
        B = B.unsqueeze(0)
        v = v.unsqueeze(0)

        # Actually start reduction!
        for i in range(niter):
            # Reduce RHS
            v[:, 1:] -= mbmm(
                B[:, 1:], torch.linalg.lu_solve(lu[:, :-1], pivots[:, :-1], v[:, :-1])
            )

            # Reduce off diagonal coefficients
            B[:, 2:] = -mbmm(
                B[:, 2:],
                torch.linalg.lu_solve(lu[:, 1:-1], pivots[:, 1:-1], B[:, 1:-1]),
            )

            # Shuffle dimensions
            v = self._cyclic_shift(v, i)
            B = self._cyclic_shift(B, i)
            lu = self._cyclic_shift(lu, i)
            pivots = self._cyclic_shift(pivots, i)

        return B.squeeze(1)[1:], v.squeeze(1)[1:]
//  [python]
def matvec(self, v):
        """
        Complete the backsolve for a given right hand side

        Args:
            v (torch.tensor): tensor of shape (nblk, sbat, sblk, 1)
        """
        # We could do this in place if it wasn't for the pad
        self.B = pad(self.B, (0, 0, 0, 0, 0, 0, 1, 0))

        # Get the PCR blocks to actually use
        start, end, last = self._pcr_blocks()

        # Do PCR
        for s, e in zip(start, end):
            self.B[s + 1 : e], v[s + 1 : e] = self._solve_block(
                self.lu[s:e], self.pivots[s:e], self.B[s:e], v[s:e]
            )

        # To retain consistent sizes
        self.B = self.B[1:]

        # We still need to solve the first block even if last is 0

        # The actual LU solve for the solution
        v[:last] = torch.solve(v[:last], torch.lu_unpack(self.lu[:last], self.pivots[:last]))

        # Now take over for Thomas
        for i in range(last, self.nblk):
            # The .clone() here should not be necessary, but for whatever
            # reason torch autograd give the usual "in place" complaint
            # without it...
            v[i] = torch.solve(
                v[i] - torch.bmm(self.B[i - 1], v[i - 1].clone()), torch.lu_unpack(self.lu[i], self.pivots[i])
            )

        return v
//  [python]
def matvec(self, v):
        """
        Complete the backsolve for a given right hand side

        Args:
            v (torch.tensor): tensor of shape (nblk, sbat, sblk, 1)
        """
        # We could do this in place if it wasn't for the pad
        self.B = pad(self.B, (0, 0, 0, 0, 0, 0, 1, 0))

        # Get the PCR blocks to actually use
        start, end, last = self._pcr_blocks()

        # Do PCR
        for s, e in zip(start, end):
            self.B[s + 1 : e], v[s + 1 : e] = self._solve_block(
                self.lu[s:e], self.pivots[s:e], self.B[s:e], v[s:e]
            )

        # To retain consistent sizes
        self.B = self.B[1:]

        # We still need to solve the first block even if last is 0

        # The actual LU solve for the solution
        v[:last] = torch.linalg.lu_solve(self.lu[:last], self.pivots[:last], v[:last])

        # Now take over for Thomas
        for i in range(last, self.nblk):
            # The .clone() here should not be necessary, but for whatever
            # reason torch autograd give the usual "in place" complaint
            # without it...
            v[i] = torch.linalg.lu_solve(
                self.lu[i],
                self.pivots[i],
                v[i] - torch.bmm(self.B[i - 1], v[i - 1].clone()),
            )

        return v
//  [python]
def BinomialCoef(n, k):
    """Compute the binomial coefficient "n choose k".

    n: number of trials
    k: number of successes

    Returns: float
    """
    return scipy.misc.comb(n, k)
//  [python]
def BinomialCoef(n, k):
    """Compute the binomial coefficient "n choose k".

    n: number of trials
    k: number of successes

    Returns: float
    """
    return scipy.special.comb(n, k)
//  [python]
def num_related_pairs(self):
        total = 0
        for c in self.must_equiv_classes:
            total += scipy.misc.comb(len(c), 2)
        return int(total)
//  [python]
def num_related_pairs(self):
        total = 0
        for c in self.must_equiv_classes:
            total += scipy.special.comb(len(c), 2)
        return int(total)
//  [python]
def getSize(self, d, n):
    if n <= 0:
      return 1 if d == 0 else 0
    elif d == 0:
      return 1
    elif d < 0:
      return 0
    else:
      return sum([2**k * scipy.misc.comb(d-1+k, d-1, exact=True)
                  for k in range(n)])
//  [python]
def getSize(self, d, n):
    if n <= 0:
      return 1 if d == 0 else 0
    elif d == 0:
      return 1
    elif d < 0:
      return 0
    else:
      return sum([2**k * scipy.special.comb(d-1+k, d-1, exact=True)
                  for k in range(n)])
//  [python]
def collect_uniform_log(self, n):
        self.data = []
        for i in range(n):
            x = self.Sim.get_new_context()
            K = self.Sim.get_num_actions()
            L = self.Sim.L
            A = np.random.choice(range(K), L, replace=False)

            rsub = self.Sim.get_base_rewards(A)
            r = self.Sim.get_slate_reward(A)
            all_r = self.Sim.get_all_rewards()

            self.data.append(LogEntry(x, A, rsub, r, all_r, 1.0/(scipy.misc.comb(K,L)*scipy.misc.factorial(L)), 1.0*L/K*np.ones(L)))
//  [python]
def collect_uniform_log(self, n):
        self.data = []
        for i in range(n):
            x = self.Sim.get_new_context()
            K = self.Sim.get_num_actions()
            L = self.Sim.L
            A = np.random.choice(range(K), L, replace=False)

            rsub = self.Sim.get_base_rewards(A)
            r = self.Sim.get_slate_reward(A)
            all_r = self.Sim.get_all_rewards()

            self.data.append(LogEntry(x, A, rsub, r, all_r, 1.0/(scipy.special.comb(K,L)*scipy.special.factorial(L)), 1.0*L/K*np.ones(L)))
//  [python]
def _munp(self, n, c):
        k = arange(0,n+1)
        val = (-1.0/c)**n * sum(comb(n,k)*(-1)**k / (1.0-c*k),axis=0)
        return where(c*n < 1, val, inf)
//  [python]
def _munp(self, n, c):
        k = arange(0,n+1)
        vals = 1.0/c**n * sum(comb(n,k) * (-1)**k * special.gamma(c*k + 1),axis=0)
        return where(c*n > -1, vals, inf)
//  [python]
def _munp(self, n, c):
        k = arange(0,n+1)
        vals = 1.0/c**n * sum(special.comb(n,k) * (-1)**k * special.gamma(c*k + 1),axis=0)
        return where(c*n > -1, vals, inf)
//  [python]
def _ell(A, m):
    """
    A helper function for expm_2009.

    Parameters
    ----------
    A : linear operator
        A linear operator whose norm of power we care about.
    m : int
        The power of the linear operator

    Returns
    -------
    value : int
        A value related to a bound.

    """
    p = 2*m + 1

    # The c_i are explained in (2.2) and (2.6) of the 2005 expm paper.
    # They are coefficients of terms of a generating function series expansion.
    abs_c_recip = scipy.misc.comb(2*p, p, exact=True) * math.factorial(2*p + 1)

    # This is explained after Eq. (1.2) of the 2009 expm paper.
    # It is the "unit roundoff" of IEEE double precision arithmetic.
    u = 2**-53

    # Estimate the 1-norm of the matrix power.
    est = _onenormest_matrix_power(abs(A), p)

    # Treat zero norm as a special case.
    if not est:
        return 0

    alpha = est / (_exact_1_norm(A) * abs_c_recip)
    log2_alpha_div_u = np.log2(alpha/u)
    value = int(np.ceil(log2_alpha_div_u / (2 * m)))
    return max(value, 0)
//  [python]
def _ell(A, m):
    """
    A helper function for expm_2009.

    Parameters
    ----------
    A : linear operator
        A linear operator whose norm of power we care about.
    m : int
        The power of the linear operator

    Returns
    -------
    value : int
        A value related to a bound.

    """
    p = 2*m + 1

    # The c_i are explained in (2.2) and (2.6) of the 2005 expm paper.
    # They are coefficients of terms of a generating function series expansion.
    abs_c_recip = scipy.special.comb(2*p, p, exact=True) * math.factorial(2*p + 1)

    # This is explained after Eq. (1.2) of the 2009 expm paper.
    # It is the "unit roundoff" of IEEE double precision arithmetic.
    u = 2**-53

    # Estimate the 1-norm of the matrix power.
    est = _onenormest_matrix_power(abs(A), p)

    # Treat zero norm as a special case.
    if not est:
        return 0

    alpha = est / (_exact_1_norm(A) * abs_c_recip)
    log2_alpha_div_u = np.log2(alpha/u)
    value = int(np.ceil(log2_alpha_div_u / (2 * m)))
    return max(value, 0)
//  [python]
def _kolmog1(x,n):
    if x <= 0:
        return 0
    if x >= 1:
        return 1
    j = np.arange(np.floor(n*(1-x))+1)
    return 1 - x * np.sum(np.exp(np.log(misc.comb(n,j))
                                       + (n-j) * np.log(1-x-j/float(n))
                                       + (j-1) * np.log(x+j/float(n))))
//  [python]
def _kolmog1(x,n):
    if x <= 0:
        return 0
    if x >= 1:
        return 1
    j = np.arange(np.floor(n*(1-x))+1)
    return 1 - x * np.sum(np.exp(np.log(scipy.special.comb(n,j))
                                       + (n-j) * np.log(1-x-j/float(n))
                                       + (j-1) * np.log(x+j/float(n))))
//  [python]
def eval_gof( self, data):
        probs = self.eval(data.levels)
        expected = probs * data.Ntrials
        # Compute various goodness of fit statistics
        LL = -2*sum((data.Ncorr*np.log(expected/(data.Ncorr+np.finfo(float).eps))
            +(data.Ntrials-data.Ncorr)*np.log((data.Ntrials-expected)/(data.Ntrials-data.Ncorr+np.finfo(float).eps))));
        X2 = sum((data.Ncorr-expected)**2./expected/(1.-probs))

        # Adding eps to avoid log(0) Nans
        self.prinsNLL = -sum( data.Ncorr*np.log(probs+np.finfo(float).eps)+(data.Ntrials-data.Ncorr)*np.log(1.-probs+np.finfo(float).eps) )

        # Treutwein/Strasburger 1999 Eq 6 (likelihood of the data)
        L_ts = 2**(sum( data.Ntrials ))
        LL_ts = 0.0
        #L_ts = 1.0
        for level in np.arange( len(data.levels) ):
            # TODO: is right to use observed data or function values?: next two lines can chg to try fitted
            thisN = data.Ntrials[level]
            thisCorr = data.Ncorr[level]
            L_ts *= misc.comb( thisN, thisCorr ) * (probs[level]**thisCorr) * (1.0 - probs[level])**(thisN-thisCorr) 
            LL_ts += np.log(misc.comb( thisN, thisCorr )) + thisCorr*np.log(probs[level]) +np.log(1.0 - probs[level])*(thisN-thisCorr) 

        #TODO: This is how Prins' clamps the lapse.  Parameterize.
        if (self.params[self.PARAM_UPPER] < 0) or (self.params[self.PARAM_UPPER] > 0.05):
            self.prinsNLL=np.inf

        return probs,LL,X2,L_ts,LL_ts,self.prinsNLL
//  [python]
def eval_gof( self, data):
        probs = self.eval(data.levels)
        expected = probs * data.Ntrials
        # Compute various goodness of fit statistics
        LL = -2*sum((data.Ncorr*np.log(expected/(data.Ncorr+np.finfo(float).eps))
            +(data.Ntrials-data.Ncorr)*np.log((data.Ntrials-expected)/(data.Ntrials-data.Ncorr+np.finfo(float).eps))));
        X2 = sum((data.Ncorr-expected)**2./expected/(1.-probs))

        # Adding eps to avoid log(0) Nans
        self.prinsNLL = -sum( data.Ncorr*np.log(probs+np.finfo(float).eps)+(data.Ntrials-data.Ncorr)*np.log(1.-probs+np.finfo(float).eps) )

        # Treutwein/Strasburger 1999 Eq 6 (likelihood of the data)
        L_ts = 2**(sum( data.Ntrials ))
        LL_ts = 0.0
        #L_ts = 1.0
        for level in np.arange( len(data.levels) ):
            # TODO: is right to use observed data or function values?: next two lines can chg to try fitted
            thisN = data.Ntrials[level]
            thisCorr = data.Ncorr[level]
            L_ts *= scipy.special.comb( thisN, thisCorr ) * (probs[level]**thisCorr) * (1.0 - probs[level])**(thisN-thisCorr) 
            LL_ts += np.log(scipy.special.comb( thisN, thisCorr )) + thisCorr*np.log(probs[level]) +np.log(1.0 - probs[level])*(thisN-thisCorr) 

        #TODO: This is how Prins' clamps the lapse.  Parameterize.
        if (self.params[self.PARAM_UPPER] < 0) or (self.params[self.PARAM_UPPER] > 0.05):
            self.prinsNLL=np.inf

        return probs,LL,X2,L_ts,LL_ts,self.prinsNLL
//  [python]
def marginal_cdf(self, y, n, alpha, beta):
        cdf = 0.0
        for i in range(y + 1):
            cdf += sc.misc.comb(n, y) * beta_fxn(y + alpha, n - y + beta) / beta_fxn(alpha, beta)
        return cdf
//  [python]
def marginal_cdf(self, y, n, alpha, beta):
        cdf = 0.0
        for i in range(y + 1):
            cdf += sc.special.comb(n, y) * beta_fxn(y + alpha, n - y + beta) / beta_fxn(alpha, beta)
        return cdf
//  [python]
def get_accuracy(series_groundtruth, series_parsedlog, debug=False):
    """ Compute accuracy metrics between log parsing results and ground truth
    
    Arguments
    ---------
        series_groundtruth : pandas.Series
            A sequence of groundtruth event Ids
        series_parsedlog : pandas.Series
            A sequence of parsed event Ids
        debug : bool, default False
            print error log messages when set to True

    Returns
    -------
        precision : float
        recall : float
        f_measure : float
        accuracy : float
    """
    series_groundtruth_valuecounts = series_groundtruth.value_counts()
    real_pairs = 0
    for count in series_groundtruth_valuecounts:
        if count > 1:
            real_pairs += scipy.misc.comb(count, 2)

    series_parsedlog_valuecounts = series_parsedlog.value_counts()
    parsed_pairs = 0
    for count in series_parsedlog_valuecounts:
        if count > 1:
            parsed_pairs += scipy.misc.comb(count, 2)

    accurate_pairs = 0
    accurate_events = 0 # determine how many lines are correctly parsed
    for parsed_eventId in series_parsedlog_valuecounts.index:
        logIds = series_parsedlog[series_parsedlog == parsed_eventId].index
        series_groundtruth_logId_valuecounts = series_groundtruth[logIds].value_counts()
        error_eventIds = (parsed_eventId, series_groundtruth_logId_valuecounts.index.tolist())
        error = True
        if series_groundtruth_logId_valuecounts.size == 1:
            groundtruth_eventId = series_groundtruth_logId_valuecounts.index[0]
            if logIds.size == series_groundtruth[series_groundtruth == groundtruth_eventId].size:
                accurate_events += logIds.size
                error = False
        if error and debug:
            print('(parsed_eventId, groundtruth_eventId) =', error_eventIds, 'failed', logIds.size, 'messages')
        for count in series_groundtruth_logId_valuecounts:
            if count > 1:
                accurate_pairs += scipy.misc.comb(count, 2)

    precision = float(accurate_pairs) / parsed_pairs
    recall = float(accurate_pairs) / real_pairs
    f_measure = 2 * precision * recall / (precision + recall)
    accuracy = float(accurate_events) / series_groundtruth.size
    return precision, recall, f_measure, accuracy
//  [python]
def get_accuracy(series_groundtruth, series_parsedlog, debug=False):
    """ Compute accuracy metrics between log parsing results and ground truth
    
    Arguments
    ---------
        series_groundtruth : pandas.Series
            A sequence of groundtruth event Ids
        series_parsedlog : pandas.Series
            A sequence of parsed event Ids
        debug : bool, default False
            print error log messages when set to True

    Returns
    -------
        precision : float
        recall : float
        f_measure : float
        accuracy : float
    """
    series_groundtruth_valuecounts = series_groundtruth.value_counts()
    real_pairs = 0
    for count in series_groundtruth_valuecounts:
        if count > 1:
            real_pairs += scipy.special.comb(count, 2)

    series_parsedlog_valuecounts = series_parsedlog.value_counts()
    parsed_pairs = 0
    for count in series_parsedlog_valuecounts:
        if count > 1:
            parsed_pairs += scipy.special.comb(count, 2)

    accurate_pairs = 0
    accurate_events = 0 # determine how many lines are correctly parsed
    for parsed_eventId in series_parsedlog_valuecounts.index:
        logIds = series_parsedlog[series_parsedlog == parsed_eventId].index
        series_groundtruth_logId_valuecounts = series_groundtruth[logIds].value_counts()
        error_eventIds = (parsed_eventId, series_groundtruth_logId_valuecounts.index.tolist())
        error = True
        if series_groundtruth_logId_valuecounts.size == 1:
            groundtruth_eventId = series_groundtruth_logId_valuecounts.index[0]
            if logIds.size == series_groundtruth[series_groundtruth == groundtruth_eventId].size:
                accurate_events += logIds.size
                error = False
        if error and debug:
            print('(parsed_eventId, groundtruth_eventId) =', error_eventIds, 'failed', logIds.size, 'messages')
        for count in series_groundtruth_logId_valuecounts:
            if count > 1:
                accurate_pairs += scipy.special.comb(count, 2)

    precision = float(accurate_pairs) / parsed_pairs
    recall = float(accurate_pairs) / real_pairs
    f_measure = 2 * precision * recall / (precision + recall)
    accuracy = float(accurate_events) / series_groundtruth.size
    return precision, recall, f_measure, accuracy
//  [python]
def surfaceForcingDer(self, order, der):
        """Calculate forcing F in equation
        u_t^<order>(der)-( Av u_z^<order> )^(der+1) = F^<order>(der)    at surface z=0
        """
        jmax = self.input.v('grid', 'maxIndex', 'x')
        fmax = self.input.v('grid', 'maxIndex', 'f')

        forcing = np.zeros((jmax+1, 1, fmax+1), dtype=complex)

        # forcing from barotropic pressure gradient
        if der == 0:
            forcing += self.input.v('G')*self.input.d('zeta'+str(order), range(0, jmax+1), [0], range(0, fmax+1), dim='x')

        #  forcing by advection; only include this in the reconstruction if the equation at 'order' contained advection
        if 'adv' in self.input.getKeysOf('u'+str(order)):
            for order1 in range(0, order):
                order2 = order-order1-1
                for i in range(0, der+1):
                    u = self.surf_u_der[:, :, :, order1, i]
                    ux = ny.derivative(self.surf_u_der[:, :, :, order2, der-i], 'x', self.input.slice('grid'))
                    forcing += scipy.misc.comb(der, i)*ny.complexAmplitudeProduct(u, ux, 2)

                    if i == 0:
                        wstr = 'w'+str(order1)
                        w = self.input.v(wstr, range(0, jmax+1), [0], range(0, fmax+1))
                    else:
                        Bu = self.input.v('B', range(0, jmax+1)).reshape((jmax+1, 1, 1))*self.surf_u_der[:, :, :, order1, i-1]
                        w = ny.derivative(Bu, 'x', self.input.slice('grid'))/self.input.v('B', range(0, jmax+1)).reshape((jmax+1, 1, 1))
                    uz = self.surf_u_der[:, :, :, order2, der-i+1]
                    forcing += scipy.misc.comb(der, i)*ny.complexAmplitudeProduct(w, uz, 2)

        # TODO
        #if 'baroc' in self.submodulesToRun:
        #if 'densitydrift' in self.submodulesToRun:

        return forcing
//  [python]
def surfaceForcingDer(self, order, der):
        """Calculate forcing F in equation
        u_t^<order>(der)-( Av u_z^<order> )^(der+1) = F^<order>(der)    at surface z=0
        """
        jmax = self.input.v('grid', 'maxIndex', 'x')
        fmax = self.input.v('grid', 'maxIndex', 'f')

        forcing = np.zeros((jmax+1, 1, fmax+1), dtype=complex)

        # forcing from barotropic pressure gradient
        if der == 0:
            forcing += self.input.v('G')*self.input.d('zeta'+str(order), range(0, jmax+1), [0], range(0, fmax+1), dim='x')

        #  forcing by advection; only include this in the reconstruction if the equation at 'order' contained advection
        if 'adv' in self.input.getKeysOf('u'+str(order)):
            for order1 in range(0, order):
                order2 = order-order1-1
                for i in range(0, der+1):
                    u = self.surf_u_der[:, :, :, order1, i]
                    ux = ny.derivative(self.surf_u_der[:, :, :, order2, der-i], 'x', self.input.slice('grid'))
                    forcing += scipy.special.comb(der, i)*ny.complexAmplitudeProduct(u, ux, 2)

                    if i == 0:
                        wstr = 'w'+str(order1)
                        w = self.input.v(wstr, range(0, jmax+1), [0], range(0, fmax+1))
                    else:
                        Bu = self.input.v('B', range(0, jmax+1)).reshape((jmax+1, 1, 1))*self.surf_u_der[:, :, :, order1, i-1]
                        w = ny.derivative(Bu, 'x', self.input.slice('grid'))/self.input.v('B', range(0, jmax+1)).reshape((jmax+1, 1, 1))
                    uz = self.surf_u_der[:, :, :, order2, der-i+1]
                    forcing += scipy.special.comb(der, i)*ny.complexAmplitudeProduct(w, uz, 2)

        # TODO
        #if 'baroc' in self.submodulesToRun:
        #if 'densitydrift' in self.submodulesToRun:

        return forcing
//  [python]
def _ell(A, m):
    """
    A helper function for expm_2009.

    Parameters
    ----------
    A : linear operator
        A linear operator whose norm of power we care about.
    m : int
        The power of the linear operator

    Returns
    -------
    value : int
        A value related to a bound.

    """
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected A to be like a square matrix')

    p = 2*m + 1

    # The c_i are explained in (2.2) and (2.6) of the 2005 expm paper.
    # They are coefficients of terms of a generating function series expansion.
    choose_2p_p = scipy.misc.comb(2*p, p, exact=True)
    abs_c_recip = float(choose_2p_p * math.factorial(2*p + 1))

    # This is explained after Eq. (1.2) of the 2009 expm paper.
    # It is the "unit roundoff" of IEEE double precision arithmetic.
    u = 2**-53

    # Compute the one-norm of matrix power p of abs(A).
    A_abs_onenorm = _onenorm_matrix_power_nnm(abs(A), p)

    # Treat zero norm as a special case.
    if not A_abs_onenorm:
        return 0

    alpha = A_abs_onenorm / (_onenorm(A) * abs_c_recip)
    log2_alpha_div_u = np.log2(alpha/u)
    value = int(np.ceil(log2_alpha_div_u / (2 * m)))
    return max(value, 0)
//  [python]
def _ell(A, m):
    """
    A helper function for expm_2009.

    Parameters
    ----------
    A : linear operator
        A linear operator whose norm of power we care about.
    m : int
        The power of the linear operator

    Returns
    -------
    value : int
        A value related to a bound.

    """
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected A to be like a square matrix')

    p = 2*m + 1

    # The c_i are explained in (2.2) and (2.6) of the 2005 expm paper.
    # They are coefficients of terms of a generating function series expansion.
    choose_2p_p = scipy.special.comb(2*p, p, exact=True)
    abs_c_recip = float(choose_2p_p * math.factorial(2*p + 1))

    # This is explained after Eq. (1.2) of the 2009 expm paper.
    # It is the "unit roundoff" of IEEE double precision arithmetic.
    u = 2**-53

    # Compute the one-norm of matrix power p of abs(A).
    A_abs_onenorm = _onenorm_matrix_power_nnm(abs(A), p)

    # Treat zero norm as a special case.
    if not A_abs_onenorm:
        return 0

    alpha = A_abs_onenorm / (_onenorm(A) * abs_c_recip)
    log2_alpha_div_u = np.log2(alpha/u)
    value = int(np.ceil(log2_alpha_div_u / (2 * m)))
    return max(value, 0)
//  [python]
def nbmf(x, N, p): # negative binomial modelling function
    y = comb(x, N - 1, exact=False) * (p ** N) * ((1 - p) ** (x - N + 1))
    return y
//  [python]
def nbrff(t, x, y, p): # negative binomial fitting function
    # return ((gamma(t[0] + x - 1) / (gamma(t[0] - 1) * gamma(x + 1))) * (t[1] ** t[0]) * ((1 - t[1]) ** x)) - y
    # return ((gamma(x+1)/(gamma(t[0]-1)*gamma(x-t[0]+1)))*(t[1]**t[0])*((1-t[1])**(x-t[0]+1))) - y
    return (comb(x, t[0] - 1, exact=False) * (p ** t[0]) * ((1 - p) ** (x - t[0] + 1))) - y
//  [python]
def nbrff(t, x, y, p): # negative binomial fitting function
    return (comb(x, t[0] - 1, exact=False) * (p ** t[0]) * ((1 - p) ** (x - t[0] + 1))) - y
//  [python]
def ztnb(self,r=5,p=0.5,max_length=20):
		"""
		Weights are sampled from a zero truncated negative binomial.
		"""
		probs = [0.0] 
		for k in range(1,max_length+1):
			probability = scipy.misc.comb(k + r -1,k) * (p ** k) * ((1.0  -p) ** r)
			probs.append(probability)
		self.weights = probs
//  [python]
def ztnb(self,r=5,p=0.5,max_length=20):
		"""
		Weights are sampled from a zero truncated negative binomial.
		"""
		probs = [0.0] 
		for k in range(1,max_length+1):
			probability = scipy.special.comb(k + r -1,k) * (p ** k) * ((1.0  -p) ** r)
			probs.append(probability)
		self.weights = probs
//  [python]
def mixture_decomp(w,l):
    k = w.shape[0]
    M = np.zeros((np.round(scipy.misc.comb(k, l)), k))
    i = 0
    for it in itertools.combinations(range(k), l):
        M[i,it] = 1
        i += 1
    
    (x,res) = scipy.optimize.nnls(M.T, l*w)
    return (M, x)
//  [python]
def mixture_decomp(w,l):
    k = w.shape[0]
    M = np.zeros((np.round(scipy.special.comb(k, l)), k))
    i = 0
    for it in itertools.combinations(range(k), l):
        M[i,it] = 1
        i += 1
    
    (x,res) = scipy.optimize.nnls(M.T, l*w)
    return (M, x)
//  [python]
def newDataAvailable(trackedPersons):
    # Collect track positions in matrix (rows = tracks, cols = x and y coordinates)
    trackCount = len(trackedPersons.tracks)
    trackPositionsMatrix = extractTrackPositions(trackedPersons)      
    maxDistance = rospy.get_param('~_max_distance', 3.0)
    trackDistances = scipy.spatial.distance.pdist(trackPositionsMatrix)

    # Prepare output SocialRelations message
    socialRelations = SocialRelations()
    socialRelations.header = trackedPersons.header

    # Generate one SocialRelation per pair of tracks
    for t1index in xrange(0, trackCount):
        for t2index in xrange(t1index+1, trackCount):
            distanceIndex = scipy.misc.comb(trackCount, 2) - scipy.misc.comb(trackCount - t1index, 2) + (t2index - t1index - 1) # see docs on squareform()
            trackDistance = trackDistances[distanceIndex]
            mappedTrackDistance = 1.0 - min(trackDistance, maxDistance) / maxDistance 

            socialRelation = SocialRelation()
            socialRelation.track1_id = trackedPersons.tracks[t1index].track_id
            socialRelation.track2_id = trackedPersons.tracks[t2index].track_id
            socialRelation.type = SocialRelation.TYPE_SPATIAL
            socialRelation.strength = mappedTrackDistance

            socialRelations.elements.append(socialRelation)

    pub.publish(socialRelations)
//  [python]
def newDataAvailable(trackedPersons):
    # Collect track positions in matrix (rows = tracks, cols = x and y coordinates)
    trackCount = len(trackedPersons.tracks)
    trackPositionsMatrix = extractTrackPositions(trackedPersons)      
    maxDistance = rospy.get_param('~_max_distance', 3.0)
    trackDistances = scipy.spatial.distance.pdist(trackPositionsMatrix)

    # Prepare output SocialRelations message
    socialRelations = SocialRelations()
    socialRelations.header = trackedPersons.header

    # Generate one SocialRelation per pair of tracks
    for t1index in xrange(0, trackCount):
        for t2index in xrange(t1index+1, trackCount):
            distanceIndex = scipy.special.comb(trackCount, 2) - scipy.special.comb(trackCount - t1index, 2) + (t2index - t1index - 1) # see docs on squareform()
            trackDistance = trackDistances[distanceIndex]
            mappedTrackDistance = 1.0 - min(trackDistance, maxDistance) / maxDistance 

            socialRelation = SocialRelation()
            socialRelation.track1_id = trackedPersons.tracks[t1index].track_id
            socialRelation.track2_id = trackedPersons.tracks[t2index].track_id
            socialRelation.type = SocialRelation.TYPE_SPATIAL
            socialRelation.strength = mappedTrackDistance

            socialRelations.elements.append(socialRelation)

    pub.publish(socialRelations)
//  [python]
def n_bib(balls,bins):
    return scipy.misc.comb(balls+bins-1,balls)
//  [python]
def n_bib(balls,bins):
    return scipy.special.comb(balls+bins-1,balls)
//  [python]
def __call__(self, u, d=0):
        """
        Calculate the point corresponding to given parameter.
        :param u: Target parameter.
        :param d: Degree of derivation.
        :type d: int
        :return: Value at u with d times derivation.
        """

        # TODO: Optimize the calculation of derivatives.

        aw = np.copy(list(map(lambda der: self.spl(u, der), range(d + 1))))
        ck = np.empty((d + 1, 3), float)

        for k in range(d + 1):
            v = aw[k][:3]
            for i in range(1, k + 1):
                v -= comb(k, i) * aw[i][-1] * ck[k - i]
            ck[k] = v / aw[0][-1]

        return ck[d]
//  [python]
def __call__(self, u, d=0):
        """
        Calculate the point corresponding to given parameter.
        :param u: Target parameter.
        :param d: Degree of derivation.
        :type d: int
        :return: Value at u with d times derivation.
        """

        # TODO: Optimize the calculation of derivatives.

        aw = np.copy(list(map(lambda der: self.spl(u, der), range(d + 1))))
        ck = np.empty((d + 1, 3), float)

        for k in range(d + 1):
            v = aw[k][:3]
            for i in range(1, k + 1):
                v -= scipy.special.comb(k, i) * aw[i][-1] * ck[k - i]
            ck[k] = v / aw[0][-1]

        return ck[d]
//  [python]
def choose(n, k):
    import scipy.misc
    return scipy.misc.comb(n, k, True)
//  [python]
def choose(n, k):
    import scipy.special
    return scipy.special.comb(n, k, True)
//  [python]
def __init__(self, bsdim = 4, center = False, start=None, stop=None, axes=['b', 0, 1, 'c']):
        self.args = locals()

        bsdim_tot = int(np.sum([scipy.misc.comb(bsdim, i) for i in range(bsdim+1)]))

        indices = sum([list(combinations(range(bsdim), i)) for i in range(bsdim+1)], [])

        Ahorz = [np.zeros([bsdim,bsdim]) for i in range(bsdim_tot)]
        Avert = [np.zeros([bsdim,bsdim]) for i in range(bsdim_tot)]

        #Horizontal
        for i, ind in enumerate(indices):
            if len(ind)>0:
                Ahorz[i][ind,:]=1

        #Vertical
        for i, ind in enumerate(indices):
            if len(ind)>0:
                Avert[i][:,ind]=1

        self.bars = Avert
        self.stripes = Ahorz
        self.bars_stripes = np.concatenate([self.bars,self.stripes])
        self.bars_stripes_labels = np.array([0]*len(Avert)+[1]*len(Ahorz))

        def dimshuffle(b01c):
            """
            .. todo::

                WRITEME
            """
            default = ('b', 0, 1, 'c')
            return b01c.transpose(*[default.index(axis) for axis in axes])

        topo_view = self.bars_stripes
        y = np.atleast_2d(self.bars_stripes_labels).T

        y_labels = len(np.unique(y))

        m, r, c = topo_view.shape
        assert r == bsdim
        assert c == bsdim
        topo_view = topo_view.reshape(m, r, c, 1)

        if center:
            topo_view -= topo_view.mean(axis=0)

        super(Bars_Stripes, self).__init__(topo_view = dimshuffle(topo_view), y=y,
                                    axes=axes, y_labels=y_labels)

        assert not N.any(N.isnan(self.X))

        if start is not None:
            assert start >= 0
            if stop > self.X.shape[0]:
                raise ValueError('stop=' + str(stop) + '>' +
                                 'm=' + str(self.X.shape[0]))
            assert stop > start
            self.X = self.X[start:stop, :]
            if self.X.shape[0] != stop - start:
                raise ValueError("X.shape[0]: %d. start: %d stop: %d"
                                 % (self.X.shape[0], start, stop))
            if len(self.y.shape) > 1:
                self.y = self.y[start:stop, :]
            else:
                self.y = self.y[start:stop]
            assert self.y.shape[0] == stop - start
//  [python]
def __init__(self, bsdim = 4, center = False, start=None, stop=None, axes=['b', 0, 1, 'c']):
        self.args = locals()

        bsdim_tot = int(np.sum([scipy.special.comb(bsdim, i) for i in range(bsdim+1)]))

        indices = sum([list(combinations(range(bsdim), i)) for i in range(bsdim+1)], [])

        Ahorz = [np.zeros([bsdim,bsdim]) for i in range(bsdim_tot)]
        Avert = [np.zeros([bsdim,bsdim]) for i in range(bsdim_tot)]

        #Horizontal
        for i, ind in enumerate(indices):
            if len(ind)>0:
                Ahorz[i][ind,:]=1

        #Vertical
        for i, ind in enumerate(indices):
            if len(ind)>0:
                Avert[i][:,ind]=1

        self.bars = Avert
        self.stripes = Ahorz
        self.bars_stripes = np.concatenate([self.bars,self.stripes])
        self.bars_stripes_labels = np.array([0]*len(Avert)+[1]*len(Ahorz))

        def dimshuffle(b01c):
            """
            .. todo::

                WRITEME
            """
            default = ('b', 0, 1, 'c')
            return b01c.transpose(*[default.index(axis) for axis in axes])

        topo_view = self.bars_stripes
        y = np.atleast_2d(self.bars_stripes_labels).T

        y_labels = len(np.unique(y))

        m, r, c = topo_view.shape
        assert r == bsdim
        assert c == bsdim
        topo_view = topo_view.reshape(m, r, c, 1)

        if center:
            topo_view -= topo_view.mean(axis=0)

        super(Bars_Stripes, self).__init__(topo_view = dimshuffle(topo_view), y=y,
                                    axes=axes, y_labels=y_labels)

        assert not N.any(N.isnan(self.X))

        if start is not None:
            assert start >= 0
            if stop > self.X.shape[0]:
                raise ValueError('stop=' + str(stop) + '>' +
                                 'm=' + str(self.X.shape[0]))
            assert stop > start
            self.X = self.X[start:stop, :]
            if self.X.shape[0] != stop - start:
                raise ValueError("X.shape[0]: %d. start: %d stop: %d"
                                 % (self.X.shape[0], start, stop))
            if len(self.y.shape) > 1:
                self.y = self.y[start:stop, :]
            else:
                self.y = self.y[start:stop]
            assert self.y.shape[0] == stop - start
//  [python]
def bezier_deg_elev(crv, t):
    """
    Degree elevation of an Bezier curve
    :param crv: Bezier curve to be elevated
    :type crv: BezierCrv
    :param t: Elevation level
    :type t: int
    :return: None
    """

    if t <= 0:
        return

    nh = ph = crv.p + t + 1
    npw = np.zeros((nh, 4))
    kv = []

    '''Knots'''
    for i in range(ph):
        kv.append(crv.a)
    for i in range(ph):
        kv.append(crv.b)

    '''Control points'''
    for i in range(nh):
        for j in range(max(0, i - t), min(crv.p, i) + 1):
            cc = comb(crv.p, j, exact=True) * comb(t, i - j, exact=True) / comb(crv.p + t, i, exact=True)
            npw[i] += cc * crv.Pw[j]

    '''Update'''
    crv.reset(kv, npw)
//  [python]
def nCk(n, k):
    """n-choose-k"""
    return scipy.misc.comb(n, k, True)
//  [python]
def nCk(n, k):
    """n-choose-k"""
    return scipy.special.comb(n, k, True)
//  [python]
def etjj(self):
        j = np.arange(2, self.n_max+1)
        jChoose2 = scipy.misc.comb(j,2)

        ret = np.zeros(len(j))
        noCoalProb = np.ones(len(j))
        for pop in self.pieces:
            ret = ret + noCoalProb * pop.etjj
            noCoalProb = noCoalProb * np.exp(- pop.scaled_time * jChoose2)
        return ret
//  [python]
def etjj(self):
        j = np.arange(2, self.n_max+1)
        jChoose2 = scipy.special.comb(j,2)

        ret = np.zeros(len(j))
        noCoalProb = np.ones(len(j))
        for pop in self.pieces:
            ret = ret + noCoalProb * pop.etjj
            noCoalProb = noCoalProb * np.exp(- pop.scaled_time * jChoose2)
        return ret
//  [python]
def binomial(mask_radius=2, interpolation=4, mode='2d'):
  """ Returns a 2-D Binomial Filter for generative matrix. Interpolation for 1 px to 4 px. Has L1 norm\DC gain of 4."""
  length = 2*mask_radius+1

  K = scipy.misc.comb((length-1)*np.ones(length), np.arange(length))

  if mode == '2d':
    K = np.outer(K,K)

  return interpolation*(K/np.sum(np.abs(K)))
//  [python]
def binomial(mask_radius=2, interpolation=4, mode='2d'):
  """ Returns a 2-D Binomial Filter for generative matrix. Interpolation for 1 px to 4 px. Has L1 norm\DC gain of 4."""
  length = 2*mask_radius+1

  K = scipy.special.comb((length-1)*np.ones(length), np.arange(length))

  if mode == '2d':
    K = np.outer(K,K)

  return interpolation*(K/np.sum(np.abs(K)))
//  [python]
def bernstein_poly(i, n, t):
    """
     The Bernstein polynomial of n, i as a function of t
    """

    return comb(n, i) * ( t**(n-i) ) * (1 - t)**i
//  [python]
def ab_filter_exp_cascade(self,tau, n, step = 0.001):
    """ create an ExpCascade filter and return arrays for the coefficients """
    from scipy.misc import comb
    tau = float(tau)
    n = int(n)
    if tau < 0:
        raise Exception("Negative time constants are not implemented")
    if n < 0:
        raise Exception("Negative cascade number is not allowed")
    if tau == 0:
        a = np.array([1.0])
        b = np.array([])
        return [a,b]
    tauC = tau/float(n) if n > 0 else tau
    c = np.exp(-step/tauC)
    N = n + 1
    a = np.array([(-c)**(i)*comb(N,i) for i in range(N+1)])
    b = np.array([(1.0-c)**N])
    return [a,b]
//  [python]
def ab_filter_exp_cascade(self,tau, n, step = 0.001):
    """ create an ExpCascade filter and return arrays for the coefficients """
    from scipy.special import comb
    tau = float(tau)
    n = int(n)
    if tau < 0:
        raise Exception("Negative time constants are not implemented")
    if n < 0:
        raise Exception("Negative cascade number is not allowed")
    if tau == 0:
        a = np.array([1.0])
        b = np.array([])
        return [a,b]
    tauC = tau/float(n) if n > 0 else tau
    c = np.exp(-step/tauC)
    N = n + 1
    a = np.array([(-c)**(i)*comb(N,i) for i in range(N+1)])
    b = np.array([(1.0-c)**N])
    return [a,b]
//  [python]
def mv_hypergeometric(x, m):
    """
    x : number of draws for each category.
    m : size of each category.
    """
    x = np.asarray(x)
    m = np.asarray(m)
    return log(comb(m, x).prod() / comb(m.sum(), x.sum()))
//  [python]
def mv_hypergeometric(x, m):
    """
    x : number of draws for each category.
    m : size of each category.
    """
    x = np.asarray(x)
    m = np.asarray(m)
    return log(comb(m, x, exact=True).prod() / comb(m.sum(), x.sum(), exact=True))