def update_attack_order(self, images: "torch.Tensor", labels: "torch.Tensor", adv_val: list) -> None:
        """
        Update the specified attack ordering.

        :param images: A tensor of a batch of original inputs to be attacked.
        :param labels: A tensor of a batch of the original labels to be predicted.
        :param adv_val: Optional; A list of a batch of current attack parameters.
        """
        import torch
        import torch.nn.functional as F

        def hungarian(matrix_batch):
            sol = torch.tensor([-i for i in range(1, matrix_batch.shape[0] + 1)], dtype=torch.int32)
            for i in range(matrix_batch.shape[0]):
                topk = 1
                sol[i] = torch.topk(matrix_batch[i], topk)[1][topk - 1]
                while sol.shape != torch.unique(sol).shape:
                    topk = topk + 1
                    sol[i] = torch.topk(matrix_batch[i], topk)[1][topk - 1]
            return sol

        def sinkhorn_normalization(ori_dsm, n_iters=20):
            for _ in range(n_iters):
                ori_dsm /= ori_dsm.sum(dim=0, keepdim=True)
                ori_dsm /= ori_dsm.sum(dim=1, keepdim=True)
            return ori_dsm

        if self.attack_order == "fixed":
            if self.curr_seq.sum() == 0:
                self.fixed_order = tuple(self.enabled_attack.index(i) for i in self.fixed_order)
                self.curr_seq = torch.tensor(self.fixed_order, device=self.device)
        elif self.attack_order == "random":
            self.curr_seq = torch.randperm(self.seq_num)
        elif self.attack_order == "scheduled":
            if self.curr_seq.sum() == 0:
                self.curr_dsm = sinkhorn_normalization(torch.rand((self.seq_num, self.seq_num)))
                self.curr_seq = hungarian(self.curr_dsm)
            self.curr_dsm = self.curr_dsm.detach().requires_grad_()
            adv_img = images.clone().detach().requires_grad_()
            original_iter_num = self.max_inner_iter
            self.max_inner_iter = 3
            self._is_scheduling = True
            for tdx in range(self.seq_num):
                prev_img = adv_img.clone()
                adv_img = torch.zeros_like(adv_img)
                for idx in range(self.seq_num):
                    _adv_img, _ = self.attack_dict[idx](prev_img, adv_val[idx], labels)
                    adv_img = adv_img + self.curr_dsm[tdx][idx] * _adv_img
            self._is_scheduling = False
            self.max_inner_iter = original_iter_num
            outputs = self.model(adv_img)
            with torch.enable_grad():
                cost = F.cross_entropy(outputs, labels)

            dsm_grad = torch.autograd.grad(cost, self.curr_dsm)[0]

            prev_seq = self.curr_seq.clone()
            dsm_noise = torch.zeros_like(self.curr_dsm)
            while torch.equal(prev_seq, self.curr_seq):
                self.curr_dsm = sinkhorn_normalization(torch.exp(self.curr_dsm + dsm_grad + dsm_noise).detach())
                self.curr_seq = hungarian(self.curr_dsm.detach())
                dsm_noise = (torch.randn_like(self.curr_dsm) + 1) * 2  # Escaping local optimum
        else:
            raise ValueError()

        Update the specified attack ordering.

        :param images: A tensor of a batch of original inputs to be attacked.
        :param labels: A tensor of a batch of the original labels to be predicted.
        :param adv_val: Optional; A list of a batch of current attack parameters.
        
art/attacks/evasion/composite_adversarial_attack.py