class_docstr: Attacks a model with word substiutitions using a genetic algorithm.
  
  Args:
      pop_size (int): The population size. Defaults to 20.
      max_iters (int): The maximum number of iterations to use. Defaults to 50.
      temp (float): Temperature for softmax function used to normalize probability dist when sampling parents.
          Higher temperature increases the sensitivity to lower probability candidates.
      give_up_if_no_improvement (bool): If True, stop the search early if no candidate that improves the score is found.
      post_crossover_check (bool): If True, check if child produced from crossover step passes the constraints.
      max_crossover_retries (int): Maximum number of crossover retries if resulting child fails to pass the constraints.
          Applied only when `post_crossover_check` is set to `True`.
          Setting it to 0 means we immediately take one of the parents at random as the child upon failure.
      max_replace_times_per_index (int):  The maximum times words at the same index can be replaced in improved genetic algorithm.
docstr: Actual operation that takes `pop_member1` text and `pop_member2`
  text and mixes the two to generate crossover between `pop_member1` and
  `pop_member2`.
  
  Args:
      pop_member1 (PopulationMember): The first population member.
      pop_member2 (PopulationMember): The second population member.
  Returns:
      Tuple of `AttackedText` and a dictionary of attributes.
code: def _crossover_operation(self, pop_member1, pop_member2):
      """Actual operation that takes `pop_member1` text and `pop_member2`
      text and mixes the two to generate crossover between `pop_member1` and
      `pop_member2`.
  
      Args:
          pop_member1 (PopulationMember): The first population member.
          pop_member2 (PopulationMember): The second population member.
      Returns:
          Tuple of `AttackedText` and a dictionary of attributes.
      """
      indices_to_replace = []
      words_to_replace = []
      num_replacements_left = np.copy(
          pop_member1.attributes["num_replacements_left"]
      )
  
      # To better simulate the reproduction and biological crossover,
      # IGA randomly cut the text from two parents and concat two fragments into a new text
      # rather than randomly choose a word of each position from the two parents.
      crossover_point = np.random.randint(0, pop_member1.num_words)
      for i in range(crossover_point, pop_member1.num_words):
          indices_to_replace.append(i)
          words_to_replace.append(pop_member2.words[i])
          num_replacements_left[i] = pop_member2.attributes[
              "num_replacements_left"
          ][i]
  
      new_text = pop_member1.attacked_text.replace_words_at_indices(
          indices_to_replace, words_to_replace
      )
      return new_text, {"num_replacements_left": num_replacements_left}
  
file_path: TextAttack/textattack/search_methods/improved_genetic_algorithm.py
imports: import numpy
  from textattack.search_methods import GeneticAlgorithm, PopulationMember
label_desc: Use image node_id 4 for calling the ImprovedGeneticAlgorithm obj's underlying member method code with example usage: obj._crossover_operation(pop_member1, pop_member2) and returns: new_text,  dict