def __call__(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> tuple[np.ndarray, np.ndarray | None]:
        """
        Applies the :class:`.InverseGAN` defence upon the sample input.

        :param x: Sample input.
        :param y: Labels of the sample `x`. This function does not affect them in any way.
        :return: Defended input.
        """
        batch_size = x.shape[0]
        iteration_count = 0

        if self.inverse_gan is not None:
            logger.info("Encoding x_adv into starting z encoding")
            initial_z_encoding = self.inverse_gan.predict(x)
        else:
            logger.info("Choosing a random starting z encoding")
            initial_z_encoding = np.random.rand(batch_size, self.gan.encoding_length)

        def func_gen_gradients(z_i):
            z_i_reshaped = np.reshape(z_i, [batch_size, self.gan.encoding_length])
            grad = self.estimate_gradient(z_i_reshaped, x)
            grad = np.float64(
                grad
            )  # scipy fortran code seems to expect float64 not 32 https://github.com/scipy/scipy/issues/5832

            return grad.flatten()

        def func_loss(z_i):
            nonlocal iteration_count
            iteration_count += 1
            logging.info("Iteration: %d", iteration_count)
            z_i_reshaped = np.reshape(z_i, [batch_size, self.gan.encoding_length])
            loss = self.compute_loss(z_i_reshaped, x)

            return loss

        options_allowed_keys = [
            "disp",
            "maxcor",
            "ftol",
            "gtol",
            "eps",
            "maxfun",
            "maxiter",
            "iprint",
            "callback",
            "maxls",
        ]

        for key in kwargs:
            if key not in options_allowed_keys:
                raise KeyError(
                    f"The argument `{key}` in kwargs is not allowed as option for `scipy.optimize.minimize` using "
                    f'`method="L-BFGS-B".`'
                )

        options = kwargs.copy()
        optimized_z_encoding_flat = minimize(
            func_loss, initial_z_encoding, jac=func_gen_gradients, method="L-BFGS-B", options=options
        )
        optimized_z_encoding = np.reshape(optimized_z_encoding_flat.x, [batch_size, self.gan.encoding_length])
        y = self.gan.predict(optimized_z_encoding)

        return x, y

        Applies the :class:`.InverseGAN` defence upon the sample input.

        :param x: Sample input.
        :param y: Labels of the sample `x`. This function does not affect them in any way.
        :return: Defended input.
        
art/defences/preprocessor/inverse_gan.py