def forward(
        self,
        x: np.ndarray,
        column_pos: int | list | None = None,
        row_pos: int | list | None = None,
    ) -> np.ndarray:
        """
        Performs ablation on the input x. If no column_pos/row_pos are specified a random location will be selected.

        :param x: input data
        :param row_pos: Specifies the row index to retain the image block. Either an int to apply the same position to
                        all images in a batch, or a list of ints to apply a different row position per datapoint.
        :param column_pos: Specifies the column index to retain the image block. Either an int to apply the same
                           position to all images in a batch, or a list of ints to apply a different
                           column position per datapoint.
        :return: Data ablated at all locations aside from the specified block. Data is channel extended to indicate to a
                 model if a position is ablated.
        """
        if not self.channels_first:
            x = np.transpose(x, (0, 3, 1, 2))

        if row_pos is None:
            row_pos = random.randint(0, x.shape[2])
        if column_pos is None:
            column_pos = random.randint(0, x.shape[3])

        x = np.concatenate([x, 1.0 - x], axis=1)

        if isinstance(row_pos, list) and isinstance(column_pos, list):
            for i, (row, col) in enumerate(zip(row_pos, column_pos)):
                x[i : i + 1] = self.ablate(x[i : i + 1], row_pos=row, column_pos=col)
        elif isinstance(row_pos, int) and isinstance(column_pos, int):
            x = self.ablate(x, row_pos=row_pos, column_pos=column_pos)

        if not self.channels_first:
            x = np.transpose(x, (0, 2, 3, 1))
        return x

        Performs ablation on the input x. If no column_pos/row_pos are specified a random location will be selected.

        :param x: input data
        :param row_pos: Specifies the row index to retain the image block. Either an int to apply the same position to
                        all images in a batch, or a list of ints to apply a different row position per datapoint.
        :param column_pos: Specifies the column index to retain the image block. Either an int to apply the same
                           position to all images in a batch, or a list of ints to apply a different
                           column position per datapoint.
        :return: Data ablated at all locations aside from the specified block. Data is channel extended to indicate to a
                 model if a position is ablated.
        
art/estimators/certification/derandomized_smoothing/ablators/tensorflow.py