def diagonal_order(self, image_size, channels):
        """
        Defines a diagonal order for pixel attacks.
        order is fixed across diagonals but are randomized across channels and within the diagonal
        e.g.
        [1, 2, 5]
        [3, 4, 8]
        [6, 7, 9]

        :param image_size: image size (i.e., width or height)
        :param channels: the number of channels

        :return order: An array holding the diagonal order of pixel attacks.
        """
        x = np.arange(0, image_size).cumsum()
        order = np.zeros((image_size, image_size)).astype(ART_NUMPY_DTYPE)
        for i in range(image_size):
            order[i, : (image_size - i)] = i + x[i:]
        for i in range(1, image_size):
            reverse = order[image_size - i - 1].take(
                [i for i in range(i - 1, -1, -1)]
            )  # pylint: disable=unnecessary-comprehension
            order[i, (image_size - i) :] = image_size * image_size - 1 - reverse
        if channels > 1:
            order_2d = order
            order = np.zeros((channels, image_size, image_size))
            for i in range(channels):
                order[i, :, :] = 3 * order_2d + i
        elif channels == 1:
            order = np.expand_dims(order, axis=0)

        if self.estimator.channels_first:
            return order.reshape(1, -1).squeeze().argsort()

        return order.transpose((1, 2, 0)).reshape(1, -1).squeeze().argsort()

        Defines a diagonal order for pixel attacks.
        order is fixed across diagonals but are randomized across channels and within the diagonal
        e.g.
        [1, 2, 5]
        [3, 4, 8]
        [6, 7, 9]

        :param image_size: image size (i.e., width or height)
        :param channels: the number of channels

        :return order: An array holding the diagonal order of pixel attacks.
        
art/attacks/evasion/simba.py