def projection_l1_2(values: np.ndarray, eps: int | float | np.ndarray) -> np.ndarray:
    """
    This function computes the orthogonal projections of a batch of points on L1-balls of given radii
    The batch size is  m = values.shape[0].  The points are flattened to dimension
    n = np.prod(value.shape[1:]).  This is required to facilitate sorting.

    Starting from a vector  a = (a1,...,an)  such that  a1 >= ... >= an >= 0,  a1 + ... + an > 1,
    we first move to  a' = a - (t,...,t)  such that either a1 + ... + an >= 1 ,  an >= 0,
    and  min( a1 + ... + an  - nt - 1, an -t ) = 0.  This means  t = min( (a1 + ... + an - 1)/n, an).
    If  t = (a1 + ... + an - 1)/n , then  a' is the desired projection.  Otherwise, the problem is reduced to
    finding the projection of  (a1 - t, ... , a{n-1} - t ).

    :param values:  A batch of  m  points, each a ndarray
    :param eps:  The radii of the respective L1-balls
    :return: projections
    """
    # pylint: disable=invalid-name
    shp = values.shape
    a = values.copy()
    n = np.prod(a.shape[1:])
    m = a.shape[0]
    a = a.reshape((m, n))
    sgns = np.sign(a)
    a = np.abs(a)
    a_argsort = a.argsort(axis=1)
    a_sorted = np.zeros((m, n))
    for i in range(m):
        a_sorted[i, :] = a[i, a_argsort[i, :]]

    a_argsort_inv = a.argsort(axis=1).argsort(axis=1)
    row_sums = np.sum(a, axis=1)
    mat = np.zeros((m, 2))
    mat0 = np.zeros((m, 2))
    a_var = a_sorted.copy()
    for j in range(n):
        mat[:, 0] = (row_sums - eps) / (n - j)
        mat[:, 1] = a_var[:, j]
        mat0[:, 1] = np.min(mat, axis=1)
        min_t = np.max(mat0, axis=1)
        if np.max(min_t) < 1e-8:
            continue
        row_sums = row_sums - a_var[:, j] * (n - j)
        a_var[:, (j + 1) :] = a_var[:, (j + 1) :] - np.matmul(min_t.reshape((m, 1)), np.ones((1, n - j - 1)))
        a_var[:, j] = a_var[:, j] - min_t
    proj = np.zeros((m, n))
    for i in range(m):
        proj[i, :] = a_var[i, a_argsort_inv[i, :]]

    proj = sgns * proj
    proj = proj.reshape(shp)
    return proj

    This function computes the orthogonal projections of a batch of points on L1-balls of given radii
    The batch size is  m = values.shape[0].  The points are flattened to dimension
    n = np.prod(value.shape[1:]).  This is required to facilitate sorting.

    Starting from a vector  a = (a1,...,an)  such that  a1 >= ... >= an >= 0,  a1 + ... + an > 1,
    we first move to  a' = a - (t,...,t)  such that either a1 + ... + an >= 1 ,  an >= 0,
    and  min( a1 + ... + an  - nt - 1, an -t ) = 0.  This means  t = min( (a1 + ... + an - 1)/n, an).
    If  t = (a1 + ... + an - 1)/n , then  a' is the desired projection.  Otherwise, the problem is reduced to
    finding the projection of  (a1 - t, ... , a{n-1} - t ).

    :param values:  A batch of  m  points, each a ndarray
    :param eps:  The radii of the respective L1-balls
    :return: projections
    
art/utils.py