Returns a list of attack configs that have not yet been run the desired
  number of times.
  :param new_work_goal: dict mapping attacks to desired number of times to run
  :param work_before: dict mapping attacks to number of times they were run
    before starting this new goal. Should be prefiltered to include only
    examples that don't already meet the primary goal
  :param run_counts: dict mapping attacks to total number of times they have
    ever been run. Should be prefiltered to include only examples that don't
    already meet the primary goal

def unfinished_attack_configs(new_work_goal, work_before, run_counts,
                              log=False):
  """
  Returns a list of attack configs that have not yet been run the desired
  number of times.
  :param new_work_goal: dict mapping attacks to desired number of times to run
  :param work_before: dict mapping attacks to number of times they were run
    before starting this new goal. Should be prefiltered to include only
    examples that don't already meet the primary goal
  :param run_counts: dict mapping attacks to total number of times they have
    ever been run. Should be prefiltered to include only examples that don't
    already meet the primary goal
  """

  assert isinstance(work_before, dict), work_before

  for key in work_before:
    value = work_before[key]
    assert value.ndim == 1, value.shape
    if key in run_counts:
      assert run_counts[key].shape == value.shape

  attack_configs = []
  for attack_config in new_work_goal:
    done_now = run_counts[attack_config]
    if log:
      _logger.info(str(attack_config) +
                   " ave run count: " + str(done_now.mean()))
      _logger.info(str(attack_config) +
                   " min run count: " + str(done_now.min()))
    done_before = work_before[attack_config]
    if log:
      _logger.info(str(attack_config) + " mean work before: " +
                   str(done_before.mean()))
    # This is the vector for all examples
    new = done_now - done_before
    # The work is only done when it has been done for every example
    new = new.min()
    assert isinstance(new, (int, np.int64)), type(new)
    new_goal = new_work_goal[attack_config]
    assert isinstance(new_goal, int), type(new_goal)
    if new < new_goal:
      if log:
        _logger.info(str(attack_config) + " has run " +
                     str(new) + " of " + str(new_goal))
      attack_configs.append(attack_config)
  return attack_configs