def _get_efron_values_single(self, X, T, E, weights, beta):
        n, d = X.shape
        hessian = np.zeros((d, d))
        gradient = np.zeros((d,))
        log_lik = 0
        x_death_sum = np.zeros((d,))
        risk_phi, tie_phi = 0, 0
        risk_phi_x, tie_phi_x = np.zeros((d,)), np.zeros((d,))
        risk_phi_x_x, tie_phi_x_x = np.zeros((d, d)), np.zeros((d, d))
        weight_count = 0.0
        tied_death_counts = 0
        scores = weights * np.exp(np.dot(X, beta))
        for i in range(n - 1, -1, -1):
            ti = T[i]
            ei = E[i]
            xi = X[i]
            score = scores[i]
            w = weights[i]
            phi_i = score
            phi_x_i = phi_i * xi
            phi_x_x_i = np.outer(xi, phi_x_i)
            risk_phi = risk_phi + phi_i
            risk_phi_x = risk_phi_x + phi_x_i
            risk_phi_x_x = risk_phi_x_x + phi_x_x_i
            if ei:
                x_death_sum = x_death_sum + w * xi
                tie_phi = tie_phi + phi_i
                tie_phi_x = tie_phi_x + phi_x_i
                tie_phi_x_x = tie_phi_x_x + phi_x_x_i
                tied_death_counts += 1
                weight_count += w
            if i > 0 and T[i - 1] == ti:
                continue
            elif tied_death_counts == 0:
                continue
            weighted_average = weight_count / tied_death_counts
            if tied_death_counts > 1:
                increasing_proportion = np.arange(tied_death_counts) / tied_death_counts
                denom = 1.0 / (risk_phi - increasing_proportion * tie_phi)
                numer = risk_phi_x - np.outer(increasing_proportion, tie_phi_x)
                a1 = np.einsum("ab,i->ab", risk_phi_x_x, denom) - np.einsum(
                    "ab,i->ab", tie_phi_x_x, increasing_proportion * denom
                )
            else:
                denom = 1.0 / np.array([risk_phi])
                numer = risk_phi_x
                a1 = risk_phi_x_x * denom
            summand = numer * denom[:, None]
            a2 = summand.T.dot(summand)
            gradient = gradient + x_death_sum - weighted_average * summand.sum(0)
            log_lik = log_lik + np.dot(x_death_sum, beta) + weighted_average * np.log(denom).sum()
            hessian = hessian + weighted_average * (a2 - a1)
            tied_death_counts = 0
            weight_count = 0.0
            x_death_sum = np.zeros((d,))
            tie_phi = 0
            tie_phi_x = np.zeros((d,))
            tie_phi_x_x = np.zeros((d, d))
        return hessian, gradient, log_lik