class_docstr: This class implements the differential evolution solver
  Parameters
  ----------
  func : callable
      The objective function to be minimized.  Must be in the form
      ``f(x, *args)``, where ``x`` is the argument in the form of a 1-D array
      and ``args`` is a  tuple of any additional fixed parameters needed to
      completely specify the function.
  bounds : sequence
      Bounds for variables.  ``(min, max)`` pairs for each element in ``x``,
      defining the lower and upper bounds for the optimizing argument of
      `func`. It is required to have ``len(bounds) == len(x)``.
      ``len(bounds)`` is used to determine the number of parameters in ``x``.
  args : tuple, optional
      Any additional fixed parameters needed to
      completely specify the objective function.
  strategy : str, optional
      The differential evolution strategy to use. Should be one of:
          - 'best1bin'
          - 'best1exp'
          - 'rand1exp'
          - 'randtobest1exp'
          - 'currenttobest1exp'
          - 'best2exp'
          - 'rand2exp'
          - 'randtobest1bin'
          - 'currenttobest1bin'
          - 'best2bin'
          - 'rand2bin'
          - 'rand1bin'
      The default is 'best1bin'
  maxiter : int, optional
      The maximum number of generations over which the entire population is
      evolved. The maximum number of function evaluations (with no polishing)
      is: ``(maxiter + 1) * popsize * len(x)``
  popsize : int, optional
      A multiplier for setting the total population size.  The population has
      ``popsize * len(x)`` individuals (unless the initial population is
      supplied via the `init` keyword).
  tol : float, optional
      Relative tolerance for convergence, the solving stops when
      ``np.std(pop) <= atol + tol * np.abs(np.mean(population_energies))``,
      where and `atol` and `tol` are the absolute and relative tolerance
      respectively.
  mutation : float or tuple(float, float), optional
      The mutation constant. In the literature this is also known as
      differential weight, being denoted by F.
      If specified as a float it should be in the range [0, 2].
      If specified as a tuple ``(min, max)`` dithering is employed. Dithering
      randomly changes the mutation constant on a generation by generation
      basis. The mutation constant for that generation is taken from
      U[min, max). Dithering can help speed convergence significantly.
      Increasing the mutation constant increases the search radius, but will
      slow down convergence.
  recombination : float, optional
      The recombination constant, should be in the range [0, 1]. In the
      literature this is also known as the crossover probability, being
      denoted by CR. Increasing this value allows a larger number of mutants
      to progress into the next generation, but at the risk of population
      stability.
  seed : int or `np.random.RandomState`, optional
      If `seed` is not specified the `np.random.RandomState` singleton is
      used.
      If `seed` is an int, a new `np.random.RandomState` instance is used,
      seeded with `seed`.
      If `seed` is already a `np.random.RandomState` instance, then that
      `np.random.RandomState` instance is used.
      Specify `seed` for repeatable minimizations.
  disp : bool, optional
      Display status messages
  callback : callable, `callback(xk, convergence=val)`, optional
      A function to follow the progress of the minimization. ``xk`` is
      the current value of ``x0``. ``val`` represents the fractional
      value of the population convergence.  When ``val`` is greater than one
      the function halts. If callback returns `True`, then the minimization
      is halted (any polishing is still carried out).
  polish : bool, optional
      If True, then `scipy.optimize.minimize` with the `L-BFGS-B` method
      is used to polish the best population member at the end. This requires
      a few more function evaluations.
  maxfun : int, optional
      Set the maximum number of function evaluations. However, it probably
      makes more sense to set `maxiter` instead.
  init : str or array-like, optional
      Specify which type of population initialization is performed. Should be
      one of:
          - 'latinhypercube'
          - 'random'
          - array specifying the initial population. The array should have
            shape ``(M, len(x))``, where len(x) is the number of parameters.
            `init` is clipped to `bounds` before use.
      The default is 'latinhypercube'. Latin Hypercube sampling tries to
      maximize coverage of the available parameter space. 'random'
      initializes the population randomly - this has the drawback that
      clustering can occur, preventing the whole of parameter space being
      covered. Use of an array to specify a population could be used, for
      example, to create a tight bunch of initial guesses in an location
      where the solution is known to exist, thereby reducing time for
      convergence.
  atol : float, optional
      Absolute tolerance for convergence, the solving stops when
      ``np.std(pop) <= atol + tol * np.abs(np.mean(population_energies))``,
      where and `atol` and `tol` are the absolute and relative tolerance
      respectively.
docstr: Runs the DifferentialEvolutionSolver.
  Returns
  -------
  res : OptimizeResult
      The optimization result represented as a ``OptimizeResult`` object.
      Important attributes are: ``x`` the solution array, ``success`` a
      Boolean flag indicating if the optimizer exited successfully and
      ``message`` which describes the cause of the termination. See
      `OptimizeResult` for a description of other attributes. If `polish`
      was employed, and a lower minimum was obtained by the polishing,
      then OptimizeResult also contains the ``jac`` attribute.
docstr_tok: ["Runs","the","DifferentialEvolutionSolver",".","Returns","--","--","--","-","res",":","OptimizeResult","The","optimization","result","represented","as","a","``","OptimizeResult","``","object",".","Important","attributes","are",":","``","x","``","the","solution","array",",","``","success","``","a","Boolean","flag","indicating","if","the","optimizer","exited","successfully","and","``","message","``","which","describes","the","cause","of","the","termination",".","See","`","OptimizeResult","`","for","a","description","of","other","attributes",".","If","`","polish","`","was","employed",",","and","a","lower","minimum","was","obtained","by","the","polishing",",","then","OptimizeResult","also","contains","the","``","jac","``","attribute","."]
code: def solve(self):
      """
      Runs the DifferentialEvolutionSolver.
      Returns
      -------
      res : OptimizeResult
          The optimization result represented as a ``OptimizeResult`` object.
          Important attributes are: ``x`` the solution array, ``success`` a
          Boolean flag indicating if the optimizer exited successfully and
          ``message`` which describes the cause of the termination. See
          `OptimizeResult` for a description of other attributes. If `polish`
          was employed, and a lower minimum was obtained by the polishing,
          then OptimizeResult also contains the ``jac`` attribute.
      """
      nit, warning_flag = 0, False
      status_message = _status_message["success"]
  
      # The population may have just been initialized (all entries are
      # np.inf). If it has you have to calculate the initial energies.
      # Although this is also done in the evolve generator it's possible
      # that someone can set maxiter=0, at which point we still want the
      # initial energies to be calculated (the following loop isn't run).
      if np.all(np.isinf(self.population_energies)):
          self._calculate_population_energies()
  
      # do the optimisation.
      for nit in range(1, self.maxiter + 1):
          # evolve the population by a generation
          try:
              next(self)
          except StopIteration:
              warning_flag = True
              status_message = _status_message["maxfev"]
              break
  
          if self.disp:
              print(
                  f"differential_evolution step {nit}: f(x)= {self.population_energies[0]}"
              )
  
          # should the solver terminate?
          convergence = self.convergence
  
          if (
              self.callback
              and self.callback(
                  self._scale_parameters(self.population[0]),
                  convergence=self.tol / convergence,
              )
              is True
          ):
              warning_flag = True
              status_message = "callback function requested stop early by returning True"
              break
  
          intol = np.std(
              self.population_energies
          ) <= self.atol + self.tol * np.abs(
              np.mean(self.population_energies)
          )
          if warning_flag or intol:
              break
  
      else:
          status_message = _status_message["maxiter"]
          warning_flag = True
  
      de_result = OptimizeResult(
          x=self.x,
          fun=self.population_energies[0],
          nfev=self._nfev,
          nit=nit,
          message=status_message,
          success=(warning_flag is not True),
      )
  
      if self.polish:
          result = minimize(
              self.func,
              np.copy(de_result.x),
              method="L-BFGS-B",
              bounds=self.limits.T,
              args=self.args,
          )
  
          self._nfev += result.nfev
          de_result.nfev = self._nfev
  
          if result.fun < de_result.fun:
              de_result.fun = result.fun
              de_result.x = result.x
              de_result.jac = result.jac
              # to keep internal state consistent
              self.population_energies[0] = result.fun
              self.population[0] = self._unscale_parameters(result.x)
  
      return de_result
  
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from itertools import product
  from typing import List, Optional, Tuple, TYPE_CHECKING
  import numpy
  from six import string_types
  import scipy
  from scipy._lib._util import check_random_state
  from scipy.optimize import OptimizeResult, minimize
  from tqdm.auto import tqdm
  from art.config import ART_NUMPY_DTYPE
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, NeuralNetworkMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.utils import check_and_transform_label_format
label_desc: Use image node_id 7 for calling the DifferentialEvolutionSolver obj's underlying member method code with example usage: obj.solve() and returns: de_result