class_docstr: Base class for attacking 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.
class_docstr_tok: ["Base","class","for","attacking","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","."]
docstr: Perturb `pop_member` and return it. Replaces a word at a random
  (unless `index` is specified) in `pop_member`.
  
  Args:
      pop_member (PopulationMember): The population member being perturbed.
      original_result (GoalFunctionResult): Result of original sample being attacked
      index (int): Index of word to perturb.
  Returns:
      Perturbed `PopulationMember`
docstr_tok: ["Perturb","`","pop_member","`","and","return","it",".","Replaces","a","word","at","a","random","(","unless","`","index","`","is","specified",")","in","`","pop_member","`",".","Args",":","pop_member","(","PopulationMember",")",":","The","population","member","being","perturbed",".","original_result","(","GoalFunctionResult",")",":","Result","of","original","sample","being","attacked","index","(","int",")",":","Index","of","word","to","perturb",".","Returns",":","Perturbed","`","PopulationMember","`"]
code: def _perturb(self, pop_member, original_result, index=None):
      """Perturb `pop_member` and return it. Replaces a word at a random
      (unless `index` is specified) in `pop_member`.
  
      Args:
          pop_member (PopulationMember): The population member being perturbed.
          original_result (GoalFunctionResult): Result of original sample being attacked
          index (int): Index of word to perturb.
      Returns:
          Perturbed `PopulationMember`
      """
      num_words = pop_member.attacked_text.num_words
      # `word_select_prob_weights` is a list of values used for sampling one word to transform
      word_select_prob_weights = np.copy(
          self._get_word_select_prob_weights(pop_member)
      )
      non_zero_indices = np.count_nonzero(word_select_prob_weights)
      if non_zero_indices == 0:
          return pop_member
      iterations = 0
      while iterations < non_zero_indices:
          if index:
              idx = index
          else:
              w_select_probs = word_select_prob_weights / np.sum(
                  word_select_prob_weights
              )
              idx = np.random.choice(num_words, 1, p=w_select_probs)[0]
  
          transformed_texts = self.get_transformations(
              pop_member.attacked_text,
              original_text=original_result.attacked_text,
              indices_to_modify=[idx],
          )
  
          if not len(transformed_texts):
              iterations += 1
              continue
  
          new_results, self._search_over = self.get_goal_results(
              transformed_texts
          )
  
          diff_scores = (
              torch.Tensor([r.score for r in new_results])
              - pop_member.result.score
          )
          if len(diff_scores) and diff_scores.max() > 0:
              idx_with_max_score = diff_scores.argmax()
              pop_member = self._modify_population_member(
                  pop_member,
                  transformed_texts[idx_with_max_score],
                  new_results[idx_with_max_score],
                  idx,
              )
              return pop_member
  
          word_select_prob_weights[idx] = 0
          iterations += 1
  
          if self._search_over:
              break
  
      return pop_member
  
imports: from abc import ABC, abstractmethod
  import numpy
  import torch
  from textattack.goal_function_results import GoalFunctionResultStatus
  from textattack.search_methods import PopulationBasedSearch, PopulationMember
  from textattack.shared.validators import transformation_consists_of_word_swaps
label_desc: Use image node_id 4 for calling the GeneticAlgorithm obj's underlying member method code with example usage: obj._perturb(pop_member, original_result, index) and returns: pop_member, pop_member, pop_member