<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def log_likelihood(C, T):
 r"""Log-likelihood of the count matrix given a transition matrix. Parameters C : (M, M) ndarray or scipy.sparse matrix Count matrix T : (M, M) ndarray orscipy.sparse matrix Transition matrix Returns ------- logL : float Log-likelihood of the count matrix Notes ----- The likelihood of a set of observed transition counts :math:`C=(c_{ij})` for a given matrix of transition counts :math:`T=(t_{ij})` is given by .. math:: L(C|P)=\prod_{i=1}^{M} \left( \prod_{j=1}^{M} p_{ij}^{c_{ij}} \right) The log-likelihood is given by .. math:: l(C|P)=\sum_{i,j=1}^{M}c_{ij} \log p_{ij}. The likelihood describes the probability of making an observation :math:`C` for a given model :math:`P`. Examples -------- References .. [1] Prinz, J H, H Wu, M Sarich, B Keller, M Senne, M Held, J D Chodera, C Schuette and F Noe. 2011. Markov models of molecular kinetics: Generation and validation. J Chem Phys 134: 174105 """

    if issparse(C) and issparse(T):
        return sparse.likelihood.log_likelihood(C, T)
    else:
        # use the dense likelihood calculator for all other cases
        # if a mix of dense/sparse C/T matrices is used, then both
        # will be converted to ndarrays.
        if not isinstance(C, np.ndarray):
            C = np.array(C)
        if not isinstance(T, np.ndarray):
            T = np.array(T)
        # computation is still efficient, because we only use terms
        # for nonzero elements of T
        nz = np.nonzero(T)
        return np.dot(C[nz], np.log(T[nz]))