'Returns the gradient of the log partial likelihood evaluated
at `params`, using the Efron method to handle tied times.'

def efron_gradient(self, params):

    surv = self.surv
    grad = 0.0
    for stx in range(surv.nstrat):
        strat_ix = surv.stratum_rows[stx]
        exog_s = surv.exog_s[stx]
        linpred = np.dot(exog_s, params)
        if (surv.offset_s is not None):
            linpred += surv.offset_s[stx]
        linpred -= linpred.max()
        e_linpred = np.exp(linpred)
        (xp0, xp1) = (0.0, 0.0)
        uft_ix = surv.ufailt_ix[stx]
        nuft = len(uft_ix)
        for i in range(nuft)[::(-1)]:
            ix = surv.risk_enter[stx][i]
            if (len(ix) > 0):
                v = exog_s[ix, :]
                xp0 += e_linpred[ix].sum()
                xp1 += (e_linpred[ix][:, None] * v).sum(0)
            ixf = uft_ix[i]
            if (len(ixf) > 0):
                v = exog_s[ixf, :]
                xp0f = e_linpred[ixf].sum()
                xp1f = (e_linpred[ixf][:, None] * v).sum(0)
                grad += v.sum(0)
                m = len(ixf)
                J = (np.arange(m, dtype=np.float64) / m)
                numer = (xp1 - np.outer(J, xp1f))
                denom = (xp0 - np.outer(J, xp0f))
                ratio = (numer / denom)
                rsum = ratio.sum(0)
                grad -= rsum
            ix = surv.risk_exit[stx][i]
            if (len(ix) > 0):
                v = exog_s[ix, :]
                xp0 -= e_linpred[ix].sum()
                xp1 -= (e_linpred[ix][:, None] * v).sum(0)
    return grad
