2024-10-24 00:11:45,395 [ERROR] Type error while initializing 'DeepFool': DeepFool requires an estimator derived from <class 'art.estimators.estimator.BaseEstimator'> and <class 'art.estimators.classification.classifier.ClassGradientsMixin'>, the provided classifier is an instance of <class 'NoneType'> and is derived from (<class 'object'>,).. Check parameter compatibility.
2024-10-24 00:11:45,395 [ERROR] Failed to apply adversarial attack: DeepFool requires an estimator derived from <class 'art.estimators.estimator.BaseEstimator'> and <class 'art.estimators.classification.classifier.ClassGradientsMixin'>, the provided classifier is an instance of <class 'NoneType'> and is derived from (<class 'object'>,).
2024-10-24 00:11:45,395 [INFO] All adversarial attack tests completed.
import abc
import logging
from typing import Any, Dict, Type, Union,Optional,Tuple
import sys
import numpy as np


from art.attacks.attack import EvasionAttack
from art.attacks.evasion.adversarial_patch.adversarial_patch import AdversarialPatch
from art.attacks.evasion.adversarial_patch.adversarial_patch_numpy import AdversarialPatchNumpy
from art.attacks.evasion.adversarial_patch.adversarial_patch_tensorflow import AdversarialPatchTensorFlowV2
from art.attacks.evasion.adversarial_patch.adversarial_patch_pytorch import AdversarialPatchPyTorch
from art.attacks.evasion.adversarial_texture.adversarial_texture_pytorch import AdversarialTexturePyTorch
from art.attacks.evasion.adversarial_asr import CarliniWagnerASR
from art.attacks.evasion.auto_attack import AutoAttack
from art.attacks.evasion.auto_projected_gradient_descent import AutoProjectedGradientDescent
from art.attacks.evasion.auto_conjugate_gradient import AutoConjugateGradient
from art.attacks.evasion.brendel_bethge import BrendelBethgeAttack
from art.attacks.evasion.boundary import BoundaryAttack
from art.attacks.evasion.composite_adversarial_attack import CompositeAdversarialAttackPyTorch
from art.attacks.evasion.carlini import CarliniL2Method, CarliniLInfMethod, CarliniL0Method
from art.attacks.evasion.decision_tree_attack import DecisionTreeAttack
from art.attacks.evasion.deepfool import DeepFool
from art.attacks.evasion.dpatch import DPatch
from art.attacks.evasion.dpatch_robust import RobustDPatch
from art.attacks.evasion.elastic_net import ElasticNet
from art.attacks.evasion.fast_gradient import FastGradientMethod
from art.attacks.evasion.frame_saliency import FrameSaliencyAttack
from art.attacks.evasion.feature_adversaries.feature_adversaries_numpy import FeatureAdversariesNumpy
from art.attacks.evasion.feature_adversaries.feature_adversaries_pytorch import FeatureAdversariesPyTorch
from art.attacks.evasion.feature_adversaries.feature_adversaries_tensorflow import FeatureAdversariesTensorFlowV2
from art.attacks.evasion.geometric_decision_based_attack import GeoDA
from art.attacks.evasion.graphite.graphite_blackbox import GRAPHITEBlackbox
from art.attacks.evasion.graphite.graphite_whitebox_pytorch import GRAPHITEWhiteboxPyTorch
from art.attacks.evasion.hclu import HighConfidenceLowUncertainty
from art.attacks.evasion.hop_skip_jump import HopSkipJump
from art.attacks.evasion.imperceptible_asr.imperceptible_asr import ImperceptibleASR
from art.attacks.evasion.imperceptible_asr.imperceptible_asr_pytorch import ImperceptibleASRPyTorch
from art.attacks.evasion.iterative_method import BasicIterativeMethod
from art.attacks.evasion.laser_attack.laser_attack import LaserAttack
from art.attacks.evasion.lowprofool import LowProFool
from art.attacks.evasion.momentum_iterative_method import MomentumIterativeMethod
from art.attacks.evasion.newtonfool import NewtonFool
from art.attacks.evasion.overload.overload import OverloadPyTorch
from art.attacks.evasion.pe_malware_attack import MalwareGDTensorFlow
from art.attacks.evasion.pixel_threshold import PixelAttack
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent import ProjectedGradientDescent
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_numpy import (
    ProjectedGradientDescentNumpy,
)
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_pytorch import (
    ProjectedGradientDescentPyTorch,
)
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_tensorflow_v2 import (
    ProjectedGradientDescentTensorFlowV2,
)
from art.attacks.evasion.over_the_air_flickering.over_the_air_flickering_pytorch import OverTheAirFlickeringPyTorch
from art.attacks.evasion.saliency_map import SaliencyMapMethod
from art.attacks.evasion.shadow_attack import ShadowAttack
from art.attacks.evasion.shapeshifter import ShapeShifter
from art.attacks.evasion.simba import SimBA
from art.attacks.evasion.spatial_transformation import SpatialTransformation
from art.attacks.evasion.square_attack import SquareAttack
from art.attacks.evasion.pixel_threshold import ThresholdAttack
from art.attacks.evasion.universal_perturbation import UniversalPerturbation
from art.attacks.evasion.targeted_universal_perturbation import TargetedUniversalPerturbation
from art.attacks.evasion.virtual_adversarial import VirtualAdversarialMethod
from art.attacks.evasion.wasserstein import Wasserstein
from art.attacks.evasion.zoo import ZooAttack
from art.attacks.evasion.sign_opt import SignOPTAttack

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)],
)
logger = logging.getLogger(__name__)




# Define AttackType as a Type that can be any subclass of EvasionAttack
AttackType = Type[EvasionAttack]

# Parameters dictionary as provided
parameters: Dict[str, Dict[str, Any]] = {
'AdversarialPatch': {
    'classifier': None,
    'rotation_max': 22.5,
    'scale_min': 0.1,
    'scale_max': 1.0,
    'learning_rate': 5.0, 
    'max_iter': 500,
    'batch_size': 16,
    'patch_shape': None, 
    'targeted': True,
    'verbose': True},

'AdversarialPatchNumpy': {
    'classifier': None, 'target': 0, 
    'rotation_max': 22.5, 
    'scale_min': 0.1, 
    'scale_max': 1.0, 
    'learning_rate': 5.0, 
    'max_iter': 500, 
    'clip_patch': None, 
    'batch_size': 16, 
    'targeted': True, 
    'verbose': True},
'AdversarialPatchTensorFlowV2': {
    'classifier': None, 
    'rotation_max': 22.5, 
    'scale_min': 0.1, 
    'scale_max': 1.0, 
    'learning_rate': 5.0, 
    'max_iter': 500, 
    'batch_size': 16, 
    'patch_shape': None,
    'optimizer': 'Adam', 
    'targeted': True, 
    'summary_writer': False, 
    'verbose': True}, 
'AdversarialPatchPyTorch': {
    'estimator': None, 
    'rotation_max': 22.5, 
    'scale_min': 0.1, 
    'scale_max': 1.0, 
    'distortion_scale_max': 0.0, 
    'learning_rate': 5.0, 
    'max_iter': 500, 
    'batch_size': 16, 
    'patch_shape': (3, 224, 224), 
    'patch_location': None, 
    'patch_type': 'circle', 
    'optimizer': 'Adam', 
    'targeted': True,
    'summary_writer': False, 
    'verbose': True},
'AdversarialTexturePyTorch': {
    'estimator': None, 
    'patch_height': None, 
    'patch_width': None, 
    'x_min': 0, 
    'y_min': 0, 
    'step_size': 0.00392156862745098, 
    'max_iter': 500, 
    'batch_size': 16, 
    'summary_writer': False, 
    'verbose': True}, 
'CarliniWagnerASR': {
    'estimator': None, 
    'eps': 2000.0, 
    'learning_rate': 100.0, 
    'max_iter': 1000, 
    'decrease_factor_eps': 0.8, 
    'num_iter_decrease_eps': 10,
    'batch_size': 16}, 
'AutoAttack': {
    'estimator': None, 
    'norm': np.inf, 
    'eps': 0.3, 
    'eps_step': 0.1, 
    'attacks': None, 
    'batch_size': 32, 
    'estimator_orig': None, 
    'targeted': False, 
    'parallel': False},
 'AutoProjectedGradientDescent': {
    'estimator': None, 
    'norm': np.inf, 
    'eps': 0.3, 
    'eps_step': 0.1, 
    'max_iter': 100,
    'targeted': False, 
    'nb_random_init': 5, 
    'batch_size': 32, 
    'loss_type': None, 
    'verbose': True}, 
'AutoConjugateGradient': {
    'estimator': None, 
    'norm': np.inf, 
    'eps': 0.3, 
    'eps_step': 0.1, 
    'max_iter': 100, 
    'targeted': False, 
    'nb_random_init': 5, 
    'batch_size': 32, 
    'loss_type': None, 
    'verbose': True},
'BrendelBethgeAttack': {
    'estimator': None, 
    'norm': np.inf, 
    'targeted': False, 
    'overshoot': 1.1, 
    'steps': 10, 
    'lr': 0.001, 
    'lr_decay': 0.5, 
    'lr_num_decay': 20, 
    'momentum': 0.8, 
    'binary_search_steps': 10, 
    'init_size': 100, 
    'batch_size': 32},
'BoundaryAttack': {
    'estimator': None, 
    'batch_size': 64, 
    'targeted': True, 
    'delta': 0.01, 
    'epsilon': 0.01, 
    'step_adapt': 0.667, 
    'max_iter': 5000, 
    'num_trial': 25, 
    'sample_size': 20, 
    'init_size': 100, 
    'min_epsilon': 0.0, 
    'verbose': True},
'CompositeAdversarialAttackPyTorch': {
    'classifier': None, 
    'enabled_attack': (0, 1, 2, 3, 4, 5), 
    'hue_epsilon': (-3.141592653589793, 3.141592653589793), 
    'sat_epsilon': (0.7, 1.3), 
    'rot_epsilon': (-10.0, 10.0), 
    'bri_epsilon': (-0.2, 0.2), 
    'con_epsilon': (0.7, 1.3), 
    'pgd_epsilon': (-0.03137254901960784, 0.03137254901960784), 
    'early_stop': True, 
    'max_iter': 5, 
    'max_inner_iter': 10, 
    'attack_order': 'scheduled', 
    'batch_size': 1, 
    'verbose': True}, 
'CarliniL2Method': {
    'classifier': None, 
    'confidence': 0.0, 
    'targeted': False, 
    'learning_rate': 0.01, 
    'binary_search_steps': 10, 
    'max_iter': 10, 
    'initial_const': 0.01, 
    'max_halving': 5, 
    'max_doubling': 5, 
    'batch_size': 1, 
    'verbose': True}, 
'CarliniLInfMethod': {
    'classifier': None, 
    'confidence': 0.0, 
    'targeted': False, 
    'learning_rate': 0.01, 
    'max_iter': 10, 
    'decrease_factor': 0.9, 
    'initial_const': 1e-05, 
    'largest_const': 20.0, 
    'const_factor': 2.0, 
    'batch_size': 1, 
    'verbose': True}, 
'CarliniL0Method': {
    'classifier': None, 
    'confidence': 0.0, 
    'targeted': False, 
    'learning_rate': 0.01, 
    'binary_search_steps': 10, 
    'max_iter': 10, 
    'initial_const': 0.01, 
    'mask': None, 
    'warm_start': True, 
    'max_halving': 5, 
    'max_doubling': 5, 
    'batch_size': 1, 
    'verbose': True}, 
'DecisionTreeAttack': {
    'classifier': None, 
    'offset': 0.001, 
    'verbose': True},
'DeepFool': {
    'classifier': None, 
    'max_iter': 100, 
    'epsilon': 1e-06, 
    'nb_grads': 10, 
    'batch_size': 1, 
    'verbose': True}, 
'DPatch': {
    'estimator': None, 
    'patch_shape': (40, 40, 3), 
    'learning_rate': 5.0, 
    'max_iter': 500, 
    'batch_size': 16, 
    'verbose': True},
'RobustDPatch': {
    'estimator': None, 
    'patch_shape': (40, 40, 3), 
    'patch_location': (0, 0), 
    'crop_range': (0, 0), 
    'brightness_range': (1.0, 1.0), 
    'rotation_weights': (1, 0, 0, 0), 
    'sample_size': 1, 
    'learning_rate': 5.0, 
    'max_iter': 500, 
    'batch_size': 16, 
    'targeted': False, 
    'summary_writer': False, 
    'verbose': True}, 
'ElasticNet': {
    'classifier': None, 
    'confidence': 0.0, 
    'targeted': False, 
    'learning_rate': 0.01, 
    'binary_search_steps': 9, 
    'max_iter': 100, 
    'beta': 0.001, 
    'initial_const': 0.001,
    'batch_size': 1, 
    'decision_rule': 'EN', 
    'verbose': True},
'FastGradientMethod': {
    'estimator': None, 
    'norm': np.inf, 
    'eps': 0.3, 
    'eps_step': 0.1, 
    'targeted': False, 
    'num_random_init': 0, 
    'batch_size': 32, 
    'minimal': False, 
    'summary_writer': False}, 
'FrameSaliencyAttack': {
    'classifier': None, 
    'attacker': None, 
    'method': 'iterative_saliency', 
    'frame_index': 1, 
    'batch_size': 1, 
    'verbose': True}, 
'FeatureAdversariesNumpy': {
    'classifier': None, 
    'delta': None, 
    'layer': None, 
    'batch_size': 32}, 
'FeatureAdversariesPyTorch': {
    'estimator': None, 
    'delta': None, 
    'optimizer': None, 
    'optimizer_kwargs': None, 
    'lambda_': 0.0, 
    'layer': -1, 
    'max_iter': 100, 
    'batch_size': 32, 
    'step_size': None, 
    'random_start': False, 
    'verbose': True}, 
'FeatureAdversariesTensorFlowV2': {
    'estimator': None, 
    'delta': None, 
    'optimizer': None, 
    'optimizer_kwargs': None, 
    'lambda_': 0.0, 
    'layer': -1, 
    'max_iter': 100, 
    'batch_size': 32, 
    'step_size': None, 
    'random_start': False, 
    'verbose': True}, 
'GeoDA': {
    'estimator': None, 
    'batch_size': 64, 
    'norm': 2, 
    'sub_dim': 10, 
    'max_iter': 4000, 
    'bin_search_tol': 0.1, 
    'lambda_param': 0.6, 
    'sigma': 0.0002, 
    'verbose': True}, 
'GRAPHITEBlackbox': {
    'classifier': None, 
    'noise_size': None, 
    'net_size': None, 
    'heat_patch_size': (4, 4), 
    'heat_patch_stride': (1, 1), 
    'heatmap_mode': 'Target', 
    'tr_lo': 0.65, 
    'tr_hi': 0.85, 
    'num_xforms_mask': 100, 
    'max_mask_size': -1, 
    'beta': 1.0, 
    'eta': 500, 
    'num_xforms_boost': 100, 
    'num_boost_queries': 20000, 
    'rotation_range': (-30.0, 30.0), 
    'dist_range': (0.0, 0.0), 
    'gamma_range': (1.0, 2.0), 
    'crop_percent_range': (-0.03125, 0.03125), 
    'off_x_range': (-0.03125, 0.03125), 
    'off_y_range': (-0.03125, 0.03125), 
    'blur_kernels': (0, 3), 
    'batch_size': 64}, 
'GRAPHITEWhiteboxPyTorch': {
    'classifier': None, 
    'net_size': None, 
    'min_tr': 0.8, 
    'num_xforms': 100, 
    'step_size': 0.0157, 
    'steps': 50, 
    'first_steps': 500, 
    'patch_removal_size': 4, 
    'patch_removal_interval': 2, 
    'num_patches_to_remove': 4, 
    'rand_start_epsilon_range': (-0.03137254901960784, 0.03137254901960784), 
    'rotation_range': (-30.0, 30.0), 
    'dist_range': (0.0, 0.0), 
    'gamma_range': (1.0, 2.0), 
    'crop_percent_range': (-0.03125, 0.03125), 
    'off_x_range': (-0.03125, 0.03125), 
    'off_y_range': (-0.03125, 0.03125), 
    'blur_kernels': (0, 3), 
    'batch_size': 64}, 
'HighConfidenceLowUncertainty': {
    'classifier': None, 
    'conf': 0.95, 
    'unc_increase': 100.0, 
    'min_val': 0.0, 
    'max_val': 1.0, 
    'verbose': True}, 
'HopSkipJump': {
    'classifier': None, 
    'batch_size': 64, 
    'targeted': False, 
    'norm': 2, 
    'max_iter': 50, 
    'max_eval': 10000, 
    'init_eval': 100, 
    'init_size': 100, 
    'verbose': True}, 
'ImperceptibleASR': {
    'estimator': None, 
    'masker': None, 
    'eps': 2000.0, 
    'learning_rate_1': 100.0, 
    'max_iter_1': 1000, 
    'alpha': 0.05, 
    'learning_rate_2': 1.0, 
    'max_iter_2': 4000, 
    'loss_theta_min': 0.05, 
    'decrease_factor_eps': 0.8, 
    'num_iter_decrease_eps': 10, 
    'increase_factor_alpha': 1.2, 
    'num_iter_increase_alpha': 20, 
    'decrease_factor_alpha': 0.8, 
    'num_iter_decrease_alpha': 50, 
    'batch_size': 1}, 
'ImperceptibleASRPyTorch': {
    'estimator': None, 
    'eps': 0.05, 
    'max_iter_1': 10, 'max_iter_2': 4000, 'learning_rate_1': 0.001, 'learning_rate_2': 0.0005, 'optimizer_1': None, 'optimizer_2': None, 'global_max_length': 200000, 'initial_rescale': 1.0, 'decrease_factor_eps': 0.8, 'num_iter_decrease_eps': 1, 'alpha': 1.2, 'increase_factor_alpha': 1.2, 'num_iter_increase_alpha': 20, 'decrease_factor_alpha': 0.8, 'num_iter_decrease_alpha': 20, 'win_length': 2048, 'hop_length': 512, 'n_fft': 2048, 'batch_size': 32, 'use_amp': False, 'opt_level': 'O1'}, 
'BasicIterativeMethod': {'estimator': None, 'eps': 0.3, 'eps_step': 0.1, 'max_iter': 100, 'targeted': False, 'batch_size': 32, 'verbose': True}, 'LaserAttack': {'estimator': None, 'iterations': None, 'laser_generator': None, 'image_generator': None, 'debug': None}, 'LowProFool': {'classifier': None, 'n_steps': 100, 'threshold': 0.5, 'lambd': 1.5, 'eta': 0.2, 'eta_decay': 0.98, 'eta_min': 1e-07, 'norm': 2, 'importance': 'pearson', 'verbose': False}, 
'MomentumIterativeMethod': {'estimator': None, 'norm': np.inf, 'eps': 0.3, 'eps_step': 0.1, 'decay': 1.0, 'max_iter': 100, 'targeted': False, 'batch_size': 32, 'verbose': True}, 
'NewtonFool': {'classifier': None, 'max_iter': 100, 'eta': 0.01, 'batch_size': 1, 'verbose': True}, 'OverloadPyTorch': {'estimator': None, 'eps': None, 'max_iter': None, 'num_grid': None, 'batch_size': None}, 
'MalwareGDTensorFlow': {'classifier': None, 'embedding_weights': None, 'param_dic': None, 'num_of_iterations': 10, 'l_0': 0.1, 'l_r': 1.0, 'use_sign': False, 'verbose': False}, 
'PixelAttack': {'classifier': None, 'th': None, 'es': 1, 'max_iter': 100, 'targeted': False, 'verbose': False}, 'ProjectedGradientDescent': {'estimator': None, 'norm': np.inf, 'eps': 0.3, 'eps_step': 0.1, 'decay': None, 'max_iter': 100, 'targeted': False, 'num_random_init': 0, 'batch_size': 32, 'random_eps': False, 'summary_writer': False, 'verbose': True}, 
'ProjectedGradientDescentNumpy': {'estimator': None, 'norm': np.inf, 'eps': 0.3, 'eps_step': 0.1, 'decay': None, 'max_iter': 100, 'targeted': False, 'num_random_init': 0, 'batch_size': 32, 'random_eps': False, 'summary_writer': False, 'verbose': True}, 
'ProjectedGradientDescentPyTorch': {'estimator': None, 'norm': np.inf, 'eps': 0.3, 'eps_step': 0.1, 'decay': None, 'max_iter': 100, 'targeted': False, 'num_random_init': 0, 'batch_size': 32, 'random_eps': False, 'summary_writer': False, 'verbose': True}, 
'ProjectedGradientDescentTensorFlowV2': {'estimator': None, 'norm': np.inf, 'eps': 0.3, 'eps_step': 0.1, 'decay': None, 'max_iter': 100, 'targeted': False, 'num_random_init': 0, 'batch_size': 32, 'random_eps': False, 'summary_writer': False, 'verbose': True}, 
'OverTheAirFlickeringPyTorch': {'classifier': None, 'eps_step': 0.01, 'max_iter': 30, 'beta_0': 1.0, 'beta_1': 0.5, 'beta_2': 0.5, 'loss_margin': 0.05, 'batch_size': 1, 'start_frame_index': 0, 'num_frames': None, 'round_samples': 0.0, 'targeted': False, 'verbose': True}, 
'SaliencyMapMethod': {'classifier': None, 'theta': 0.1, 'gamma': 1.0, 'batch_size': 1, 'verbose': True}, 
'ShadowAttack': {'estimator': None, 'sigma': 0.5, 'nb_steps': 300, 'learning_rate': 0.1, 'lambda_tv': 0.3, 'lambda_c': 1.0, 'lambda_s': 0.5, 'batch_size': 400, 'targeted': False, 'verbose': True}, 
'ShapeShifter': {'estimator': None, 'random_transform': None, 'box_classifier_weight': 1.0, 'box_localizer_weight': 2.0, 'rpn_classifier_weight': 1.0, 'rpn_localizer_weight': 2.0, 'box_iou_threshold': 0.5, 'box_victim_weight': 0.0, 'box_target_weight': 0.0, 'box_victim_cw_weight': 0.0, 'box_victim_cw_confidence': 0.0, 'box_target_cw_weight': 0.0, 'box_target_cw_confidence': 0.0, 'rpn_iou_threshold': 0.5, 'rpn_background_weight': 0.0, 'rpn_foreground_weight': 0.0, 'rpn_cw_weight': 0.0, 'rpn_cw_confidence': 0.0, 'similarity_weight': 0.0, 'learning_rate': 1.0, 'optimizer': 'GradientDescentOptimizer', 'momentum': 0.0, 'decay': 0.0, 'sign_gradients': False, 'random_size': 10, 'max_iter': 10, 'texture_as_input': False, 'use_spectral': True, 'soft_clip': False}, 
'SimBA': {'classifier': None, 'attack': 'dct', 'max_iter': 3000, 'order': 'random', 'epsilon': 0.1, 'freq_dim': 4, 'stride': 1, 'targeted': False, 'batch_size': 1, 'verbose': True}, 
'SpatialTransformation': {'classifier': None, 'max_translation': 0.0, 'num_translations': 1, 'max_rotation': 0.0, 'num_rotations': 1, 'verbose': True}, 'SquareAttack': {'estimator': None, 'norm': np.inf, 'adv_criterion': None, 'loss': None, 'max_iter': 100, 'eps': 0.3, 'p_init': 0.8, 'nb_restarts': 1, 'batch_size': 128, 'verbose': True}, 
'ThresholdAttack': {'classifier': None, 'th': None, 'es': 0, 'max_iter': 100, 'targeted': False, 'verbose': False}, 
'UniversalPerturbation': {'classifier': None, 'attacker': 'deepfool', 'attacker_params': None, 'delta': 0.2, 'max_iter': 20, 'eps': 10.0, 'norm': np.inf, 'batch_size': 32, 'verbose': True}, 
'TargetedUniversalPerturbation': {'classifier': None, 'attacker': 'fgsm', 'attacker_params': None, 'delta': 0.2, 'max_iter': 20, 'eps': 10.0, 'norm': np.inf}, 'VirtualAdversarialMethod': {'classifier': None, 'max_iter': 10, 'finite_diff': 1e-06, 'eps': 0.1, 'batch_size': 1, 'verbose': True}, 
'Wasserstein': {'estimator': None, 'targeted': False, 'regularization': 3000.0, 'p': 2, 'kernel_size': 5, 'eps_step': 0.1, 'norm': 'wasserstein', 'ball': 'wasserstein', 'eps': 0.3, 'eps_iter': 10, 'eps_factor': 1.1, 'max_iter': 400, 'conjugate_sinkhorn_max_iter': 400, 'projected_sinkhorn_max_iter': 400, 'batch_size': 1, 'verbose': True}, 
'ZooAttack': {'classifier': None, 'confidence': 0.0, 'targeted': False, 'learning_rate': 0.01, 'max_iter': 10, 'binary_search_steps': 1, 'initial_const': 0.001, 'abort_early': True, 'use_resize': True, 'use_importance': True, 'nb_parallel': 128, 'batch_size': 1, 'variable_h': 0.0001, 'verbose': True}, 'SignOPTAttack': {'estimator': None, 'targeted': True, 'epsilon': 0.001, 'num_trial': 100, 'max_iter': 1000, 'query_limit': 20000, 'k': 200, 'alpha': 0.2, 'beta': 0.001, 'eval_perform': False, 'batch_size': 64, 'verbose': False}
}


# Mapping from attack class names to actual classes
attack_class_mapping: Dict[str, AttackType] = {
    'AdversarialPatch': AdversarialPatch,
    'AdversarialPatchNumpy': AdversarialPatchNumpy,
    'AdversarialPatchTensorFlowV2': AdversarialPatchTensorFlowV2,
    'AdversarialPatchPyTorch': AdversarialPatchPyTorch,
    'AdversarialTexturePyTorch': AdversarialTexturePyTorch,
    'CarliniWagnerASR': CarliniWagnerASR,
    'AutoAttack': AutoAttack,
    'AutoProjectedGradientDescent': AutoProjectedGradientDescent,
    'AutoConjugateGradient': AutoConjugateGradient,
    'BrendelBethgeAttack': BrendelBethgeAttack,
    'BoundaryAttack': BoundaryAttack,
    'CompositeAdversarialAttackPyTorch': CompositeAdversarialAttackPyTorch,
    'CarliniL2Method': CarliniL2Method,
    'CarliniLInfMethod': CarliniLInfMethod,
    'CarliniL0Method': CarliniL0Method,
    'DecisionTreeAttack': DecisionTreeAttack,
    'DeepFool': DeepFool,
    'DPatch': DPatch,
    'RobustDPatch': RobustDPatch,
    'ElasticNet': ElasticNet,
    'FastGradientMethod': FastGradientMethod,
    'FrameSaliencyAttack': FrameSaliencyAttack,
    'FeatureAdversariesNumpy': FeatureAdversariesNumpy,
    'FeatureAdversariesPyTorch': FeatureAdversariesPyTorch,
    'FeatureAdversariesTensorFlowV2': FeatureAdversariesTensorFlowV2,
    'GeoDA': GeoDA,
    'GRAPHITEBlackbox': GRAPHITEBlackbox,
    'GRAPHITEWhiteboxPyTorch': GRAPHITEWhiteboxPyTorch,
    'HighConfidenceLowUncertainty': HighConfidenceLowUncertainty,
    'HopSkipJump': HopSkipJump,
    'ImperceptibleASR': ImperceptibleASR,
    'ImperceptibleASRPyTorch': ImperceptibleASRPyTorch,
    'BasicIterativeMethod': BasicIterativeMethod,
    'LaserAttack': LaserAttack,
    'LowProFool': LowProFool,
    'MomentumIterativeMethod': MomentumIterativeMethod,
    'NewtonFool': NewtonFool,
    'OverloadPyTorch': OverloadPyTorch,
    'MalwareGDTensorFlow': MalwareGDTensorFlow,
    'PixelAttack': PixelAttack,
    'ProjectedGradientDescent': ProjectedGradientDescent,
    'ProjectedGradientDescentNumpy': ProjectedGradientDescentNumpy,
    'ProjectedGradientDescentPyTorch': ProjectedGradientDescentPyTorch,
    'ProjectedGradientDescentTensorFlowV2': ProjectedGradientDescentTensorFlowV2,
    'OverTheAirFlickeringPyTorch': OverTheAirFlickeringPyTorch,
    'SaliencyMapMethod': SaliencyMapMethod,
    'ShadowAttack': ShadowAttack,
    'ShapeShifter': ShapeShifter,
    'SimBA': SimBA,
    'SpatialTransformation': SpatialTransformation,
    'SquareAttack': SquareAttack,
    'ThresholdAttack': ThresholdAttack,
    'UniversalPerturbation': UniversalPerturbation,
    'TargetedUniversalPerturbation': TargetedUniversalPerturbation,
    'VirtualAdversarialMethod': VirtualAdversarialMethod,
    'Wasserstein': Wasserstein,
    'ZooAttack': ZooAttack,
    'SignOPTAttack': SignOPTAttack,
}



def get_attack_parameters(attack_name: str) -> Dict[str, Any]:
    """
    Retrieve the parameters for the specified attack.

    Args:
        attack_name (str): The name of the attack.

    Returns:
        Dict[str, Any]: A dictionary of parameters for the attack.
    """
    params = parameters.get(attack_name, {}).copy()
    if not params:
        logger.warning(f"No parameters found for attack '{attack_name}'. Using empty defaults.")
    return params


def get_attack_class(attack_name: str) -> AttackType:
    """
    Retrieve the attack class based on the attack name.

    Args:
        attack_name (str): The name of the attack.

    Returns:
        AttackType: The corresponding attack class.

    Raises:
        ValueError: If the attack name is not recognized.
    """
    attack_class = attack_class_mapping.get(attack_name)
    if not attack_class:
        raise ValueError(f"Attack '{attack_name}' is not recognized or not supported.")
    return attack_class





def update_attack_parameters(
    existing_params: Dict[str, Any], new_params: Dict[str, Any]
) -> Dict[str, Any]:
    """
    Update existing attack parameters with new parameters provided by the user.
    Ensures that each parameter is applied only once and handles changes.

    Args:
        existing_params (Dict[str, Any]): The current attack parameters.
        new_params (Dict[str, Any]): The new parameters to apply.

    Returns:
        Dict[str, Any]: The updated attack parameters.

    Raises:
        ValueError: If a parameter in new_params is invalid or conflicts occur.
    """
    updated_params = existing_params.copy()
    for key, value in new_params.items():
        if key in updated_params:
            logger.info(
                f"Updating parameter '{key}': {updated_params[key]} -> {value}."
            )
        else:
            logger.info(f"Adding new parameter '{key}': {value}.")
        updated_params[key] = value
    return updated_params


def apply_attack(
    attack_name: str,
    classifier: Any,
    x: np.ndarray,
    y: Optional[np.ndarray] = None,
    new_params: Optional[Dict[str, Any]] = None,
) -> np.ndarray:
    """
    Apply a single adversarial attack with the ability to update attack parameters.

    Args:
        attack_name (str): The name of the attack to apply.
        classifier (Any): The classifier to attack.
        x (np.ndarray): Input data.
        y (Optional[np.ndarray]): True labels.
        new_params (Optional[Dict[str, Any]]): New parameters to update the attack.

    Returns:
        np.ndarray: Adversarial examples generated by the attack.

    Raises:
        ValueError: If the attack is not implemented for the classifier or parameters are invalid.
        TypeError: If there's a type mismatch during attack initialization.
        NotImplementedError: If the attack is not supported.
        Exception: For any other errors during the attack process.
    """
    logger.info(f"Initializing attack: {attack_name}")
    try:
        attack_class = get_attack_class(attack_name)
        if attack_class is None:
            raise NotImplementedError(
                f"The attack '{attack_name}' is not supported."
            )

        params = get_attack_parameters(attack_name)

        if new_params:
            params = update_attack_parameters(params, new_params)
        if "estimator" in list(str(params.keys())):
            params['estimator']=classifier
        elif 'classifier' in list(str(params.keys())):   
            params['classifier']=classifier
        
        # Handle special parameters if necessary
        # For specific attacks, modify parameters accordingly
        if attack_name == "AutoAttack":
            params["estimator_orig"] = classifier
        elif attack_name == "AdversarialPatchPyTorch":
            # Ensure 'estimator' is correctly set
            params["estimator"] = classifier

        # Initialize the attack with the classifier and parameters
        # Pass 'estimator' as a keyword argument to avoid conflicts
        attack = attack_class(**params)

        # Generate adversarial examples
        adversarial_examples = attack.generate(x=x, y=y)

        logger.info(f"Attack '{attack_name}' performed successfully.")
        return adversarial_examples

    except ValueError as ve:
        logger.error(f"Value error: {ve}")
        raise
    except TypeError as te:
        logger.error(
            f"Type error while initializing '{attack_name}': {te}. Check parameter compatibility."
        )
        raise
    except NotImplementedError as nie:
        logger.warning(str(nie))
        raise
    except Exception as e:
        logger.error(f"Unexpected error during '{attack_name}': {e}")
        raise

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from art.estimators.classification import PyTorchClassifier
class SimpleCNN(nn.Module):
    """A simple convolutional neural network."""

    def __init__(self, num_classes: int) -> None:
        """Initialize the CNN architecture.

        Args:
            num_classes (int): Number of output classes.
        """
        super(SimpleCNN, self).__init__()
        self.conv1: nn.Conv2d = nn.Conv2d(
            in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1
        )
        self.conv2: nn.Conv2d = nn.Conv2d(
            in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1
        )
        self.adaptive_pool: nn.AdaptiveAvgPool2d = nn.AdaptiveAvgPool2d((32, 32))
        self.fc1: nn.Linear = nn.Linear(64 * 32 * 32, 128)
        self.fc2: nn.Linear = nn.Linear(128, num_classes)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Define the forward pass.

        Args:
            x (torch.Tensor): Input tensor.

        Returns:
            torch.Tensor: Output logits.
        """
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = self.adaptive_pool(x)
        x = torch.flatten(x, 1)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x


def initialize_model(num_classes: int) -> nn.Module:
    """Initialize the CNN model.

    Args:
        num_classes (int): Number of output classes.

    Returns:
        nn.Module: Initialized model.
    """
    try:
        model = SimpleCNN(num_classes=num_classes)
        logger.info("Model initialized successfully.")
        return model
    except Exception as e:
        logger.error(f"Error initializing model: {e}")
        sys.exit(1)


def initialize_classifier(
    model: nn.Module,
    input_shape: Tuple[int, int, int],
    nb_classes: int,
    clip_values: Tuple[float, float],
    learning_rate: float = 0.001,
) -> PyTorchClassifier:
    """Initialize the ART PyTorchClassifier.

    Args:
        model (nn.Module): PyTorch model.
        input_shape (Tuple[int, int, int]): Shape of input data.
        nb_classes (int): Number of classes.
        clip_values (Tuple[float, float]): Min and max values for input data.
        learning_rate (float, optional): Learning rate for optimizer. Defaults to 0.001.

    Returns:
        PyTorchClassifier: Wrapped classifier.
    """
    try:
        loss_fn = nn.CrossEntropyLoss()
        optimizer = optim.Adam(model.parameters(), lr=learning_rate)
        classifier = PyTorchClassifier(
            model=model,
            loss=loss_fn,
            optimizer=optimizer,
            input_shape=input_shape,
            nb_classes=nb_classes,
            clip_values=clip_values,
        )
        logger.info("Classifier initialized successfully.")
        return classifier
    except Exception as e:
        logger.error(f"Error initializing classifier: {e}")
        sys.exit(1)


def generate_dummy_data(batch_size: int = 1) -> Tuple[np.ndarray, np.ndarray]:
    """Generate dummy input data and labels.

    Args:
        batch_size (int, optional): Number of samples. Defaults to 1.

    Returns:
        Tuple[np.ndarray, np.ndarray]: Inputs and labels.
    """
    try:
        # Generate random inputs as NumPy arrays
        inputs = np.random.randn(batch_size, 3, 32, 32).astype(np.float32)
        # Generate random labels between 0 and nb_classes - 1
        labels = np.random.randint(0, 1000, size=(batch_size,))
        logger.info("Dummy data generated successfully.")
        return inputs, labels
    except Exception as e:
        logger.error(f"Error generating dummy data: {e}")
        sys.exit(1)


def main() -> None:
    """Main function to execute the end-to-end attack tests."""
    logger.info("Starting end-to-end adversarial attack tests.")

    # Initialize model
    num_classes = 1000
    model = initialize_model(num_classes=num_classes)
    logger.info("Model initialized successfully.")

    # Initialize classifier
    input_shape = (3, 32, 32)
    clip_values = (0.0, 1.0)
    classifier = initialize_classifier(
        model=model,
        input_shape=input_shape,
        nb_classes=num_classes,
        clip_values=clip_values,
    )
    logger.info("Classifier initialized successfully.")

    # Generate dummy data
    inputs, labels = generate_dummy_data(batch_size=32)
    logger.info("Dummy data generated successfully.")

    # Specify the attack name
    selected_attack = 'DeepFool'  # Change as needed

    try:
        adversarial_x = apply_attack(
            attack_name=selected_attack,
            classifier=classifier,
            x=inputs,
            y=labels
        )
        print(adversarial_x.shape)
        logger.info("Adversarial attack applied successfully.")
    except Exception as e:
        logger.error(f"Failed to apply adversarial attack: {e}")

    logger.info("All adversarial attack tests completed.")


if __name__ == "__main__":
    main()