def generate(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> np.ndarray:
        """
        Generate the composite adversarial samples and return them in a Numpy array.

        :param x: An array with the original inputs to be attacked.
        :param y: An array with the original labels to be predicted.
        :return: An array holding the composite adversarial examples.
        """
        if y is None:
            raise ValueError("The argument `y` must be provided.")

        import torch

        y = check_and_transform_label_format(y, nb_classes=self.estimator.nb_classes)
        dataset = torch.utils.data.TensorDataset(
            torch.from_numpy(x.astype(ART_NUMPY_DTYPE)),
            torch.from_numpy(y.astype(ART_NUMPY_DTYPE)),
        )
        data_loader = torch.utils.data.DataLoader(
            dataset=dataset, batch_size=self.batch_size, shuffle=False, drop_last=False
        )

        # Start to compute adversarial examples.
        x_adv = x.copy().astype(ART_NUMPY_DTYPE)

        # Compute perturbations with batching.
        for batch_id, batch_all in enumerate(
            tqdm(data_loader, desc=self._description, leave=False, disable=not self.verbose)
        ):
            (batch_x, batch_y) = batch_all[0], batch_all[1]
            batch_index_1, batch_index_2 = batch_id * self.batch_size, (batch_id + 1) * self.batch_size

            x_adv[batch_index_1:batch_index_2] = self._generate_batch(x=batch_x, y=batch_y)

        logger.info(
            "Success rate of attack: %.2f%%",
            100 * compute_success(self.estimator, x, y, x_adv, batch_size=self.batch_size),
        )

        return x_adv

        Generate the composite adversarial samples and return them in a Numpy array.

        :param x: An array with the original inputs to be attacked.
        :param y: An array with the original labels to be predicted.
        :return: An array holding the composite adversarial examples.
        
art/attacks/evasion/composite_adversarial_attack.py