class_docstr: A GA Optimiser for Cartesian Product Domains. 
class_docstr_tok: ["A","GA","Optimiser","for","Cartesian","Product","Domains","."]
docstr: The mutation operator for the product domain. 
docstr_tok: ["The","mutation","operator","for","the","product","domain","."]
code: def _mutation_op(self, X, num_mutations):
      """The mutation operator for the product domain."""
      if hasattr(num_mutations, "__iter__"):
          num_mutations_for_each_x = num_mutations
      else:
          choices_for_each_mutation = np.random.choice(
              len(X), num_mutations, replace=True
          )
          num_mutations_for_each_x = [
              np.sum(choices_for_each_mutation == i)
              for i in range(len(X))
          ]
      ret = []
      # Now extend
      for idx in range(len(X)):
          ret.extend(
              self._get_mutation_for_single_x(
                  X[idx], num_mutations_for_each_x[idx]
              )
          )
      np.random.shuffle(ret)
      return ret
  
imports: from copy import copy
  import numpy
  from scipy.spatial.distance import cdist
  from ..exd.cp_domain_utils import get_processed_func_from_raw_func_for_cp_domain, load_cp_domain_from_config_file
  from ..exd.experiment_caller import ExperimentCaller, CPFunctionCaller
  from ..exd.worker_manager import SyntheticWorkerManager
  from ..exd.exd_utils import get_cp_domain_initial_qinfos
  from .ga_optimiser import GAOptimiser, ga_opt_args
  from ..utils.general_utils import project_to_bounds
  from ..utils.option_handler import load_options
label_desc: Use image node_id 4 for calling the CPGAOptimiser obj's underlying member method code with example usage: obj._mutation_op(X, num_mutations) and returns: ret