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

        :param x: An array with the original inputs.
        :param y: The target labels for the targeted perturbation. The shape of y should match the number of instances
                  in x.
        :return: An array holding the adversarial examples.
        :raises: `ValueError`: if the labels `y` are None or if the attack has not been tested for binary
                 classification with a single output classifier.
        """
        if y is None:
            raise ValueError("Labels `y` cannot be None.")

        if self.estimator.nb_classes == 2 and y.shape[1] == 1:
            raise ValueError(
                "This attack has not yet been tested for binary classification with a single output classifier."
            )

        logger.info("Computing targeted universal perturbation based on %s attack.", self.attacker)

        # Init universal perturbation
        noise = np.zeros_like(x[[0]])
        fooling_rate = 0.0
        targeted_success_rate = 0.0
        nb_instances = len(x)

        # Instantiate the middle attacker and get the predicted labels
        attacker = self._get_attack(self.attacker, self.attacker_params)
        pred_y = self.estimator.predict(x, batch_size=1)
        pred_y_max = np.argmax(pred_y, axis=1)

        # Start to generate the adversarial examples
        nb_iter = 0
        while targeted_success_rate < 1.0 - self.delta and nb_iter < self.max_iter:
            # Go through all the examples randomly
            rnd_idx = random.sample(range(nb_instances), nb_instances)

            # Go through the data set and compute the perturbation increments sequentially
            for _, (e_x, e_y) in enumerate(zip(x[rnd_idx], y[rnd_idx])):
                x_i = e_x[None, ...]
                y_i = e_y[None, ...]

                current_label = np.argmax(self.estimator.predict(x_i + noise)[0])
                target_label = np.argmax(y_i)

                if current_label != target_label:
                    # Compute adversarial perturbation
                    adv_xi = attacker.generate(x_i + noise, y=y_i)

                    new_label = np.argmax(self.estimator.predict(adv_xi)[0])

                    # If the class has changed, update v
                    if new_label == target_label:
                        noise = adv_xi - x_i

                        # Project on L_p ball
                        noise = projection(noise, self.eps, self.norm)
            nb_iter += 1

            # Apply attack and clip
            x_adv = x + noise
            if hasattr(self.estimator, "clip_values") and self.estimator.clip_values is not None:
                clip_min, clip_max = self.estimator.clip_values
                x_adv = np.clip(x_adv, clip_min, clip_max)

            # Compute the error rate
            y_adv = np.argmax(self.estimator.predict(x_adv, batch_size=1), axis=1)
            fooling_rate = np.sum(pred_y_max != y_adv) / nb_instances
            targeted_success_rate = np.sum(y_adv == np.argmax(y, axis=1)) / nb_instances

        self.fooling_rate = fooling_rate
        self.targeted_success_rate = targeted_success_rate
        self.converged = nb_iter < self.max_iter
        self.noise = noise
        logger.info("Fooling rate of universal perturbation attack: %.2f%%", 100 * fooling_rate)
        logger.info("Targeted success rate of universal perturbation attack: %.2f%%", 100 * targeted_success_rate)

        return x_adv

        Generate adversarial samples and return them in an array.

        :param x: An array with the original inputs.
        :param y: The target labels for the targeted perturbation. The shape of y should match the number of instances
                  in x.
        :return: An array holding the adversarial examples.
        :raises: `ValueError`: if the labels `y` are None or if the attack has not been tested for binary
                 classification with a single output classifier.
        
art/attacks/evasion/targeted_universal_perturbation.py