def run_batch_with_goal(sess, model, x, y, adv_x_val, criteria, attack_configs,
                        run_counts, goal, report, report_path,
                        attack_batch_size=BATCH_SIZE):
  """
  Runs attack bundling on one batch of data.
  This function is mostly intended to be called by
  `bundle_attacks_with_goal`.

  :param sess: tf.session.Session
  :param model: cleverhans.model.Model
  :param x: numpy array containing clean example inputs to attack
  :param y: numpy array containing true labels
  :param adv_x_val: numpy array containing the adversarial examples made so far
    by earlier work in the bundling process
  :param criteria: dict mapping string names of criteria to numpy arrays with
    their values for each example
    (Different AttackGoals track different criteria)
  :param run_counts: dict mapping AttackConfigs to numpy arrays reporting how
    many times they have been run on each example
  :param goal: the AttackGoal to work on
  :param report: dict, see `bundle_attacks_with_goal`
  :param report_path: str, path to save the report to
  """
  attack_config = goal.get_attack_config(attack_configs, run_counts, criteria)
  idxs = goal.request_examples(attack_config, criteria, run_counts,
                               attack_batch_size)
  x_batch = x[idxs]
  assert x_batch.shape[0] == attack_batch_size
  y_batch = y[idxs]
  assert y_batch.shape[0] == attack_batch_size
  adv_x_batch = run_attack(sess, model, x_batch, y_batch,
                           attack_config.attack, attack_config.params,
                           attack_batch_size, devices, pass_y=attack_config.pass_y)
  criteria_batch = goal.get_criteria(sess, model, adv_x_batch, y_batch,
                                     batch_size=min(attack_batch_size,
                                                    BATCH_SIZE))
  # This can't be parallelized because some orig examples are copied more
  # than once into the batch
  cur_run_counts = run_counts[attack_config]
  for batch_idx, orig_idx in enumerate(idxs):
    cur_run_counts[orig_idx] += 1
    should_copy = goal.new_wins(criteria, orig_idx, criteria_batch, batch_idx)
    if should_copy:
      adv_x_val[orig_idx] = adv_x_batch[batch_idx]
      for key in criteria:
        criteria[key][orig_idx] = criteria_batch[key][batch_idx]
      assert np.allclose(y[orig_idx], y_batch[batch_idx])
  report['bundled'] = ConfidenceReportEntry(criteria['correctness'], criteria['confidence'])

  should_save = False
  new_time = time.time()
  if hasattr(report, 'time'):
    if new_time - report.time > REPORT_TIME_INTERVAL:
      should_save = True
  else:
    should_save = True
  if should_save:
    report.time = new_time
    goal.print_progress(criteria, run_counts)
    save(criteria, report, report_path, adv_x_val)
Runs attack bundling on one batch of data.
  This function is mostly intended to be called by
  `bundle_attacks_with_goal`.

  :param sess: tf.session.Session
  :param model: cleverhans.model.Model
  :param x: numpy array containing clean example inputs to attack
  :param y: numpy array containing true labels
  :param adv_x_val: numpy array containing the adversarial examples made so far
    by earlier work in the bundling process
  :param criteria: dict mapping string names of criteria to numpy arrays with
    their values for each example
    (Different AttackGoals track different criteria)
  :param run_counts: dict mapping AttackConfigs to numpy arrays reporting how
    many times they have been run on each example
  :param goal: the AttackGoal to work on
  :param report: dict, see `bundle_attacks_with_goal`
  :param report_path: str, path to save the report to