code: def __init__(
      self,
      func,
      bounds,
      args=(),
      constraints=None,
      n=None,
      iters=None,
      callback=None,
      minimizer_kwargs=None,
      options=None,
      sampling_method="simplicial",
      workers=1,
  ):
      from scipy.stats import qmc
  
      # Input checks
      methods = ["halton", "sobol", "simplicial"]
      if (
          isinstance(sampling_method, str)
          and sampling_method not in methods
      ):
          raise ValueError(
              (
                  "Unknown sampling_method specified."
                  " Valid methods: {}"
              ).format(", ".join(methods))
          )
  
      # Split obj func if given with Jac
      try:
          if (minimizer_kwargs["jac"] is True) and (
              not callable(minimizer_kwargs["jac"])
          ):
              self.func = MemoizeJac(func)
              jac = self.func.derivative
              minimizer_kwargs["jac"] = jac
              func = self.func  # .fun
          else:
              self.func = (
                  func  # Normal definition of objective function
              )
      except (TypeError, KeyError):
          self.func = func  # Normal definition of objective function
  
      # Initiate class
      self.func = _FunctionWrapper(func, args)
      self.bounds = bounds
      self.args = args
      self.callback = callback
  
      # Bounds
      abound = np.array(bounds, float)
      self.dim = np.shape(abound)[0]  # Dimensionality of problem
  
      # Set none finite values to large floats
      infind = ~np.isfinite(abound)
      abound[infind[:, 0], 0] = -1e50
      abound[infind[:, 1], 1] = 1e50
  
      # Check if bounds are correctly specified
      bnderr = abound[:, 0] > abound[:, 1]
      if bnderr.any():
          raise ValueError(
              "Error: lb > ub in bounds {}.".format(
                  ", ".join(str(b) for b in bnderr)
              )
          )
  
      self.bounds = abound
  
      # Constraints
      # Process constraint dict sequence:
      self.constraints = constraints
      if constraints is not None:
          self.min_cons = constraints
          self.g_cons = []
          self.g_args = []
  
          # shgo internals deals with old-style constraints
          # self.constraints is used to create Complex, so need
          # to be stored internally in old-style.
          # `minimize` takes care of normalising these constraints
          # for slsqp/cobyla/trust-constr.
          self.constraints = standardize_constraints(
              constraints, np.empty(self.dim, float), "old"
          )
          for cons in self.constraints:
              if cons["type"] in ("ineq"):
                  self.g_cons.append(cons["fun"])
                  try:
                      self.g_args.append(cons["args"])
                  except KeyError:
                      self.g_args.append(())
          self.g_cons = tuple(self.g_cons)
          self.g_args = tuple(self.g_args)
      else:
          self.g_cons = None
          self.g_args = None
  
      # Define local minimization keyword arguments
      # Start with defaults
      self.minimizer_kwargs = {
          "method": "SLSQP",
          "bounds": self.bounds,
          "options": {},
          "callback": self.callback,
      }
      if minimizer_kwargs is not None:
          # Overwrite with supplied values
          self.minimizer_kwargs.update(minimizer_kwargs)
  
      else:
          self.minimizer_kwargs["options"] = {"ftol": 1e-12}
  
      if (
          self.minimizer_kwargs["method"].lower()
          in ("slsqp", "cobyla", "trust-constr")
          and (
              minimizer_kwargs is not None
              and "constraints" not in minimizer_kwargs
              and constraints is not None
          )
          or (self.g_cons is not None)
      ):
          self.minimizer_kwargs["constraints"] = self.min_cons
  
      # Process options dict
      if options is not None:
          self.init_options(options)
      else:  # Default settings:
          self.f_min_true = None
          self.minimize_every_iter = True
  
          # Algorithm limits
          self.maxiter = None
          self.maxfev = None
          self.maxev = None
          self.maxtime = None
          self.f_min_true = None
          self.minhgrd = None
  
          # Objective function knowledge
          self.symmetry = None
  
          # Algorithm functionality
          self.infty_cons_sampl = True
          self.local_iter = False
  
          # Feedback
          self.disp = False
  
      # Remove unknown arguments in self.minimizer_kwargs
      # Start with arguments all the solvers have in common
      self.min_solver_args = [
          "fun",
          "x0",
          "args",
          "callback",
          "options",
          "method",
      ]
      # then add the ones unique to specific solvers
      solver_args = {
          "_custom": ["jac", "hess", "hessp", "bounds", "constraints"],
          "nelder-mead": [],
          "powell": [],
          "cg": ["jac"],
          "bfgs": ["jac"],
          "newton-cg": ["jac", "hess", "hessp"],
          "l-bfgs-b": ["jac", "bounds"],
          "tnc": ["jac", "bounds"],
          "cobyla": ["constraints", "catol"],
          "slsqp": ["jac", "bounds", "constraints"],
          "dogleg": ["jac", "hess"],
          "trust-ncg": ["jac", "hess", "hessp"],
          "trust-krylov": ["jac", "hess", "hessp"],
          "trust-exact": ["jac", "hess"],
          "trust-constr": ["jac", "hess", "hessp", "constraints"],
      }
      method = self.minimizer_kwargs["method"]
      self.min_solver_args += solver_args[method.lower()]
  
      # Only retain the known arguments
      def _restrict_to_keys(dictionary, goodkeys):
          """Remove keys from dictionary if not in goodkeys - inplace"""
          existingkeys = set(dictionary)
          for key in existingkeys - set(goodkeys):
              dictionary.pop(key, None)
  
      _restrict_to_keys(self.minimizer_kwargs, self.min_solver_args)
      _restrict_to_keys(
          self.minimizer_kwargs["options"],
          self.min_solver_args + ["ftol"],
      )
  
      # Algorithm controls
      # Global controls
      self.stop_global = False  # Used in the stopping_criteria method
      self.break_routine = False  # Break the algorithm globally
      self.iters = iters  # Iterations to be ran
      self.iters_done = 0  # Iterations completed
      self.n = n  # Sampling points per iteration
      self.nc = 0  # n  # Sampling points to sample in current iteration
      self.n_prc = 0  # Processed points (used to track Delaunay iters)
      self.n_sampled = (
          0  # To track no. of sampling points already generated
      )
      self.fn = (
          0  # Number of feasible sampling points evaluations performed
      )
      self.hgr = 0  # Homology group rank
      # Initially attempt to build the triangulation incrementally:
      self.qhull_incremental = True
  
      # Default settings if no sampling criteria.
      if (
          (self.n is None)
          and (self.iters is None)
          and (sampling_method == "simplicial")
      ):
          self.n = 2**self.dim + 1
          self.nc = 0  # self.n
      if self.iters is None:
          self.iters = 1
      if (self.n is None) and not (sampling_method == "simplicial"):
          self.n = self.n = 100
          self.nc = 0  # self.n
      if (self.n == 100) and (sampling_method == "simplicial"):
          self.n = 2**self.dim + 1
  
      if not (
          (self.maxiter is None)
          and (self.maxfev is None)
          and (self.maxev is None)
          and (self.minhgrd is None)
          and (self.f_min_true is None)
      ):
          self.iters = None
  
      # Set complex construction mode based on a provided stopping criteria:
      # Initialise sampling Complex and function cache
      # Note that sfield_args=() since args are already wrapped in self.func
      # using the_FunctionWrapper class.
      self.HC = Complex(
          dim=self.dim,
          domain=self.bounds,
          sfield=self.func,
          sfield_args=(),
          symmetry=self.symmetry,
          constraints=self.constraints,
          workers=workers,
      )
  
      # Choose complex constructor
      if sampling_method == "simplicial":
          self.iterate_complex = self.iterate_hypercube
          self.sampling_method = sampling_method
  
      elif sampling_method in ["halton", "sobol"] or not isinstance(
          sampling_method, str
      ):
          self.iterate_complex = self.iterate_delaunay
          # Sampling method used
          if sampling_method in ["halton", "sobol"]:
              if sampling_method == "sobol":
                  self.n = int(2 ** np.ceil(np.log2(self.n)))
                  # self.n #TODO: Should always be self.n, this is
                  # unacceptable for shgo, check that nfev behaves as
                  # expected.
                  self.nc = 0
                  self.sampling_method = "sobol"
                  self.qmc_engine = qmc.Sobol(
                      d=self.dim, scramble=False, seed=0
                  )
              else:
                  self.sampling_method = "halton"
                  self.qmc_engine = qmc.Halton(
                      d=self.dim, scramble=True, seed=0
                  )
  
              def sampling_method(n, d):
                  return self.qmc_engine.random(n)
  
          else:
              # A user defined sampling method:
              self.sampling_method = "custom"
  
          self.sampling = self.sampling_custom
          self.sampling_function = sampling_method  # F(n, d)
  
      # Local controls
      self.stop_l_iter = False  # Local minimisation iterations
      self.stop_complex_iter = False  # Sampling iterations
  
      # Initiate storage objects used in algorithm classes
      self.minimizer_pool = []
  
      # Cache of local minimizers mapped
      self.LMC = LMapCache()
  
      # Initialize return object
      self.res = (
          OptimizeResult()
      )  # scipy.optimize.OptimizeResult object
      self.res.nfev = (
          0  # Includes each sampling point as func evaluation
      )
      self.res.nlfev = 0  # Local function evals for all minimisers
      self.res.nljev = 0  # Local Jacobian evals for all minimisers
      self.res.nlhev = 0
  
imports: from collections import namedtuple
  import time
  import logging
  import warnings
  import sys
  import numpy
  from scipy import spatial
  from scipy.optimize import OptimizeResult, minimize, Bounds
  from scipy.optimize._optimize import MemoizeJac
  from scipy.optimize._constraints import new_bounds_to_old
  from scipy.optimize._minimize import standardize_constraints
  from scipy._lib._util import _FunctionWrapper
  from scipy.optimize._shgo_lib._complex import Complex
label_desc: Use image node_id 1 to create a new SHGO object  with example: obj = SHGO(func, bounds, args, constraints, n, iters, callback, minimizer_kwargs, options, sampling_method, workers)