def forward(
        self, x: torch.Tensor | np.ndarray, column_pos: int | None = None, row_pos: int | None = None
    ) -> torch.Tensor:
        """
        Forward pass though the ablator. We insert a new channel to keep track of the ablation location.

        :param x: Input data
        :param column_pos: The start position of the albation
        :return: The albated input with an extra channel indicating the location of the ablation if running in
        """
        if self.original_shape is not None and x.shape[1] != self.original_shape[0] and self.algorithm == "salman2021":
            raise ValueError(f"Ablator expected {self.original_shape[0]} input channels. Recived shape of {x.shape[1]}")

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

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

        if isinstance(x, np.ndarray):
            x = torch.from_numpy(x).to(self.device)

        if self.add_ablation_mask:
            ones = torch.torch.ones_like(x[:, 0:1, :, :]).to(self.device)
            x = torch.cat([x, ones], dim=1)

        if self.additional_channels:
            x = torch.cat([x, 1.0 - x], dim=1)

        if self.original_shape is not None and x.shape[1] != self.original_shape[0] and self.additional_channels:
            raise ValueError(f"Ablator expected {self.original_shape[0]} input channels. Recived shape of {x.shape[1]}")

        ablated_x = self.ablate(x, column_pos=column_pos, row_pos=row_pos)

        if self.to_reshape:
            ablated_x = self.upsample(ablated_x)
        return ablated_x

        Forward pass though the ablator. We insert a new channel to keep track of the ablation location.

        :param x: Input data
        :param column_pos: The start position of the albation
        :return: The albated input with an extra channel indicating the location of the ablation if running in
        
art/estimators/certification/derandomized_smoothing/ablators/pytorch.py