def get_adv_malware(
        self,
        embeddings: "tf.Tensor",
        data: np.ndarray,
        labels: np.ndarray,
        fsize: np.ndarray,
        perturbation_size: np.ndarray,
        perturb_sizes: list[list[int]] | None = None,
        perturb_starts: list[list[int]] | None = None,
    ) -> np.ndarray:
        """
        Project the adversarial example back though the closest l2 vector.

        :param embeddings: Adversarially optimised embeddings
        :param labels: Labels for the data
        :param fsize: Size of the original malware
        :param data: Original data in the feature space
        :param perturbation_size: Size of the l0 attack to append (if any).
        :param perturb_sizes: List, with each element itself being a list of the start positions of a
                        perturbation regions in a sample
        :param perturb_starts: List, with each element itself being a list of the start positions of a
                         start of the perturbation regions in a sample

        :return data: Numpy array with valid data samples.
        """
        import tensorflow as tf

        for i, label in enumerate(labels):
            if label == 1:
                total_diff = 0
                m = tf.constant([1, self.param_dic["input_dim"], 1], tf.int32)

                if perturb_sizes is not None and perturb_starts is not None:
                    for size, start in zip(perturb_sizes[i], perturb_starts[i]):
                        expanded = tf.tile(tf.expand_dims(embeddings[i, start : start + size, :], axis=1), m)
                        diff = tf.norm((expanded - self.embedding_weights), axis=-1)
                        diff = tf.math.argmin(diff, axis=-1)
                        data[i, start : start + size] = diff
                        total_diff += len(diff)
                expanded = tf.tile(
                    tf.expand_dims(embeddings[i, fsize[i] : fsize[i] + perturbation_size[i], :], axis=1), m
                )
                diff = tf.norm((expanded - self.embedding_weights), axis=-1)
                diff = tf.math.argmin(diff, axis=-1)
                data[i, fsize[i] : fsize[i] + perturbation_size[i]] = diff
                total_diff += len(diff)

                # sanity check that the total number of perturbed features does
                # not exceed the total perturbation budget
                assert total_diff == self.total_perturbation[i]
        return data

        Project the adversarial example back though the closest l2 vector.

        :param embeddings: Adversarially optimised embeddings
        :param labels: Labels for the data
        :param fsize: Size of the original malware
        :param data: Original data in the feature space
        :param perturbation_size: Size of the l0 attack to append (if any).
        :param perturb_sizes: List, with each element itself being a list of the start positions of a
                        perturbation regions in a sample
        :param perturb_starts: List, with each element itself being a list of the start positions of a
                         start of the perturbation regions in a sample

        :return data: Numpy array with valid data samples.
        
art/attacks/evasion/pe_malware_attack.py