def zip_ll(data, means, M):
genes, cells = data.shape<EOL>clusters = means.shape[<NUM_LIT:1>]<EOL>ll = np.zeros((cells, clusters))<EOL>d0 = (data==<NUM_LIT:0>)<EOL>d1 = (data><NUM_LIT:0>)<EOL>for i in range(clusters):<EOL><INDENT>means_i = np.tile(means[:,i], (cells, <NUM_LIT:1>))<EOL>means_i = means_i.transpose()<EOL>L_i = np.tile(M[:,i], (cells, <NUM_LIT:1>))<EOL>L_i = L_i.transpose()<EOL>ll_0 = np.log(L_i + (<NUM_LIT:1> - L_i)*np.exp(-means_i))<EOL>ll_0 = np.where((L_i==<NUM_LIT:0>) & (means_i==<NUM_LIT:0>), -means_i, ll_0)<EOL>ll_1 = np.log(<NUM_LIT:1> - L_i) + xlogy(data, means_i) -  means_i<EOL>ll_0 = np.where(d0, ll_0, <NUM_LIT:0.0>)<EOL>ll_1 = np.where(d1, ll_1, <NUM_LIT:0.0>)<EOL>ll[:,i] = np.sum(ll_0 + ll_1, <NUM_LIT:0>)<EOL><DEDENT>return ll<EOL>
Calculates the zero-inflated Poisson log-likelihood.

Args:
    data (array): genes x cells
    means (array): genes x k
    M (array): genes x k - this is the zero-inflation parameter.

Returns:
    cells x k array of log-likelihood for each cell/cluster pair.