verl/trainer/ppo/core_algos.py
def compute_outcome_advantage(
    token_level_rewards: torch.Tensor, response_mask: torch.Tensor,
    index: np.ndarray, epsilon: float = 1e-6,
):
    """Maps the N rewards of each prompt group to N advantages."""
    scores = token_level_rewards.sum(dim=-1)
    id2score = group_by_prompt(scores, index)   # unchanged verl grouping: {prompt: (N,)}
    id2adv = {}

    with torch.no_grad():
        for idx, r in id2score.items():
            N = r.numel()

            # GRPO: standardize within the group
            id2adv[idx] = (r - r.mean()) / (r.std() + epsilon)

            # TailRL: w_(i) = sum_{k<=i} (r_(k) - r_(k-1)) / (N - k + 1)
            rs, perm = torch.sort(r)                          # ascending rewards
            w = (rs.diff(prepend=r.new_zeros(1)) / torch.arange(N, 0, -1).to(r)).cumsum(0)
            id2adv[idx] = (w - w.mean())[perm.argsort()]      # mean-center, unsort

    adv = scatter_to_batch(id2adv, index) * response_mask   # unchanged verl scatter
    return adv, adv