<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def invalidated(self, targets, invalidate_dependents=False, silent=False, fingerprint_strategy=None, topological_order=False):
 """Checks targets for invalidation, first checking the artifact cache. Subclasses call this to figure out what to work on. :API: public :param targets: The targets to check for changes. :param invalidate_dependents: If True then any targets depending on changed targets are invalidated. :param silent: If true, suppress logging information about target invalidation. :param fingerprint_strategy: A FingerprintStrategy instance, which can do per task, finer grained fingerprinting of a given Target. :param topological_order: Whether to invalidate in dependency order. If no exceptions are thrown by work in the block, the build cache is updated for the targets. Note: the artifact cache is not updated. That must be done manually. :returns: Yields an InvalidationCheck object reflecting the targets. :rtype: InvalidationCheck """

    invalidation_check = self._do_invalidation_check(fingerprint_strategy,
                                                     invalidate_dependents,
                                                     targets,
                                                     topological_order)

    self._maybe_create_results_dirs(invalidation_check.all_vts)

    if invalidation_check.invalid_vts and self.artifact_cache_reads_enabled():
      with self.context.new_workunit('cache'):
        cached_vts, uncached_vts, uncached_causes = \
          self.check_artifact_cache(self.check_artifact_cache_for(invalidation_check))
      if cached_vts:
        cached_targets = [vt.target for vt in cached_vts]
        self.context.run_tracker.artifact_cache_stats.add_hits(self._task_name, cached_targets)
        if not silent:
          self._report_targets('Using cached artifacts for ', cached_targets, '.')
      if uncached_vts:
        uncached_targets = [vt.target for vt in uncached_vts]
        self.context.run_tracker.artifact_cache_stats.add_misses(self._task_name,
                                                                 uncached_targets,
                                                                 uncached_causes)
        if not silent:
          self._report_targets('No cached artifacts for ', uncached_targets, '.')
      # Now that we've checked the cache, re-partition whatever is still invalid.
      invalidation_check = InvalidationCheck(invalidation_check.all_vts, uncached_vts)

    if not silent:
      targets = []
      for vt in invalidation_check.invalid_vts:
        targets.extend(vt.targets)

      if len(targets):
        target_address_references = [t.address.reference() for t in targets]
        msg_elements = [
          'Invalidated ',
          items_to_report_element(target_address_references, 'target'),
          '.',
        ]
        self.context.log.info(*msg_elements)

    self._update_invalidation_report(invalidation_check, 'pre-check')

    # Cache has been checked to create the full list of invalid VTs.
    # Only copy previous_results for this subset of VTs.
    if self.incremental:
      for vts in invalidation_check.invalid_vts:
        vts.copy_previous_results()

    # This may seem odd: why would we need to invalidate a VersionedTargetSet that is already
    # invalid?  But the name force_invalidate() is slightly misleading in this context - what it
    # actually does is delete the key file created at the end of the last successful task run.
    # This is necessary to avoid the following scenario:
    #
    # 1) In state A: Task suceeds and writes some output.  Key is recorded by the invalidator.
    # 2) In state B: Task fails, but writes some output.  Key is not recorded.
    # 3) After reverting back to state A: The current key is the same as the one recorded at the
    #    end of step 1), so it looks like no work needs to be done, but actually the task
    #   must re-run, to overwrite the output written in step 2.
    #
    # Deleting the file ensures that if a task fails, there is no key for which we might think
    # we're in a valid state.
    for vts in invalidation_check.invalid_vts:
      vts.force_invalidate()

    # Yield the result, and then mark the targets as up to date.
    yield invalidation_check

    self._update_invalidation_report(invalidation_check, 'post-check')

    for vt in invalidation_check.invalid_vts:
      vt.update()

    # Background work to clean up previous builds.
    if self.context.options.for_global_scope().workdir_max_build_entries is not None:
      self._launch_background_workdir_cleanup(invalidation_check.all_vts)