class_docstr: AblationFlip generator.
  
  Ablates tokens in input text to generate counterfactuals that flip the
  prediction.
  
  This generator works for both classification and regression models. In the
  case of classification models, the returned counterfactuals are guaranteed to
  have a different prediction class as the original example. In the case of
  regression models, the returned counterfactuals are guaranteed to be on the
  opposite side of a user-provided threshold as the original example.
  
  The returned counterfactuals are guaranteed to be minimal in the sense that
  no strict subset of the applied ablations would have resulted in a
  prediction flip.
  
  The number of model predictions made by this generator is upper-bounded by
  number of tokens + 2^MAX_ABLATABLE_TOKENS. Since MAX_ABLATABLE_TOKENS is a
  constant, effectively this generator makes O(n) model predictions, where n is
  the total number of tokens across all input fields.
docstr: Identify minimal sets of token albations that alter the prediction.
docstr_tok: ["Identify","minimal","sets","of","token","albations","that","alter","the","prediction","."]
code: def generate(
      self,
      example: JsonDict,
      model: lit_model.Model,
      dataset: lit_dataset.Dataset,
      config: Optional[JsonDict] = None,
  ) -> list[JsonDict]:
      """Identify minimal sets of token albations that alter the prediction."""
      del dataset  # Unused.
  
      config = config or {}
      num_examples = int(
          config.get(NUM_EXAMPLES_KEY, NUM_EXAMPLES_DEFAULT)
      )
      max_ablations = int(
          config.get(MAX_ABLATIONS_KEY, MAX_ABLATIONS_DEFAULT)
      )
      tokens_to_ignore = config.get(
          TOKENS_TO_IGNORE_KEY, TOKENS_TO_IGNORE_DEFAULT
      )
      assert (
          model is not None
      ), "Please provide a model for this generator."
  
      input_spec = model.input_spec()
      pred_key = config.get(PREDICTION_KEY, "")
      regression_thresh = float(
          config.get(REGRESSION_THRESH_KEY, REGRESSION_THRESH_DEFAULT)
      )
  
      output_spec = model.output_spec()
      assert pred_key, "Please provide the prediction key"
      assert pred_key in output_spec, "Invalid prediction key"
  
      is_regression = isinstance(
          output_spec[pred_key], types.RegressionScore
      )
      if not is_regression:
          assert isinstance(
              output_spec[pred_key], types.MulticlassPreds
          ), "Only classification or regression models are supported"
      logging.info(r"W3lc0m3 t0 Ablatl0nFl1p \o/")
      logging.info("Original example: %r", example)
  
      # Check for fields to ablate.
      fields_to_ablate = list(config.get(FIELDS_TO_ABLATE_KEY, []))
      if not fields_to_ablate:
          return []
  
      # Get model outputs.
      orig_output = list(model.predict([example]))[0]
      loo_scores = self._generate_leave_one_out_ablation_score(
          example,
          model,
          input_spec,
          output_spec,
          orig_output,
          pred_key,
          fields_to_ablate,
          tokens_to_ignore,
      )
  
      if isinstance(output_spec[pred_key], types.RegressionScore):
          ablation_idxs_generator = self._gen_ablation_idxs(
              loo_scores,
              max_ablations,
              orig_output[pred_key],
              regression_thresh,
          )
      else:
          ablation_idxs_generator = self._gen_ablation_idxs(
              loo_scores, max_ablations
          )
  
      tokens_map = {}
      for field in input_spec.keys():
          tokens = self._get_tokens(example, input_spec, field)
          if not tokens:
              continue
          tokens_map[field] = tokens
  
      successful_cfs = []
      successful_positions = []
      for ablation_idxs in ablation_idxs_generator:
          if len(successful_cfs) >= num_examples:
              return successful_cfs
  
          # If a subset of the set of tokens have already been successful in
          # obtaining a flip, we continue. This ensures that we only consider
          # sets of tokens that are minimal.
          if self._subset_exists(
              set(ablation_idxs), successful_positions
          ):
              continue
  
          # Create counterfactual and obtain model prediction.
          cf = self._create_cf(
              example, input_spec, ablation_idxs
          )  # pytype: disable=wrong-arg-types  # enable-nested-classes
          cf_output = list(model.predict([cf]))[0]
  
          # Check if counterfactual results in a prediction flip.
          if cf_utils.is_prediction_flip(
              cf_output,
              orig_output,
              output_spec,
              pred_key,
              regression_thresh,
          ):
              # Prediction flip found!
              cf_utils.update_prediction(
                  cf, cf_output, output_spec, pred_key
              )
              cf[ABLATED_TOKENS_KEY] = str(
                  [
                      f"{field}[{tokens_map[field][idx]}]"
                      for field, idx in ablation_idxs
                  ]
              )
              successful_cfs.append(cf)
              successful_positions.append(set(ablation_idxs))
      return successful_cfs
  
imports: import collections
  from collections.abc import Iterator
  import itertools
  from typing import Any, Optional
  from absl import logging
  from lit_nlp.api import components
  from lit_nlp.api import dataset
  from lit_nlp.api import model
  from lit_nlp.api import types
  from lit_nlp.components import cf_utils
  from lit_nlp.lib import utils
label_desc: Use image node_id 10 for calling the AblationFlip obj's underlying member method code with example usage: obj.generate(example, model, dataset, config) and returns: successful_cfs, list, successful_cfs