def caa_linf(
        self, data: "torch.Tensor", eta: "torch.Tensor", labels: "torch.Tensor"
    ) -> tuple["torch.Tensor", "torch.Tensor"]:
        """
        Compute the adversarial examples for L-infinity (PGD) component.

        :param data: A tensor of a batch of original inputs to be attacked.
        :param eta: The perturbation in the L-infinity ball.
        :param labels: A tensor of a batch of the original labels to be predicted.
        :return: The perturbed data.
        """
        import torch
        import torch.nn.functional as F

        sur_data = data.detach()
        adv_data = data.detach().requires_grad_()
        ori_is_attacked = self.is_attacked.clone()
        for _ in range(self.max_inner_iter):
            outputs = self.model(adv_data)

            if not self._is_scheduling and self.early_stop:
                cur_pred = outputs.max(1, keepdim=True)[1].squeeze()
                self.is_attacked = torch.logical_or(
                    ori_is_attacked, cur_pred != labels.max(1, keepdim=True)[1].squeeze()
                )

            with torch.enable_grad():
                cost = F.cross_entropy(outputs, labels)
            _grad = torch.autograd.grad(cost, adv_data)[0]
            if not self._is_scheduling:
                _grad[self.is_attacked] = 0
            adv_data = adv_data + self.step_size_pool[5] * torch.sign(_grad)
            eta = torch.clamp(adv_data - sur_data, min=self.eps_pool[5][0], max=self.eps_pool[5][1])
            adv_data = torch.clamp(sur_data + eta, min=0.0, max=1.0).detach_().requires_grad_()

        return adv_data, eta

        Compute the adversarial examples for L-infinity (PGD) component.

        :param data: A tensor of a batch of original inputs to be attacked.
        :param eta: The perturbation in the L-infinity ball.
        :param labels: A tensor of a batch of the original labels to be predicted.
        :return: The perturbed data.
        
art/attacks/evasion/composite_adversarial_attack.py