code: def compute_dp_sgd_privacy_statement(
      number_of_examples: int,
      batch_size: int,
      num_epochs: float,
      noise_multiplier: float,
      delta: float,
      used_microbatching: bool = True,
      max_examples_per_user: Optional[int] = None,
      accountant_type: AccountantType = AccountantType.RDP,
  ) -> str:
      """Produces a privacy report summarizing the DP guarantee.
  
      Args:
        number_of_examples: Total number of examples in the dataset. For DP-SGD, an
          "example" corresponds to one row in a minibatch. E.g., for sequence models
          this would be a sequence of maximum length.
        batch_size: The number of examples in a batch. This should be the number of
          examples in a batch, *regardless of whether/how they are grouped into
          microbatches*.
        num_epochs: The number of epochs of training. May be fractional.
        noise_multiplier: The ratio of the Gaussian noise stddev to the l2 clip norm
          at each round. It is assumed that the noise_multiplier is constant
          although the clip norm may be variable if, for example, adaptive clipping
          is used.
        delta: The target delta.
        used_microbatching: Whether microbatching was used (with microbatch size
          greater than one). Microbatching inflates sensitivity by a factor of two
          in add-or-remove-one adjacency DP. (See "How to DP-fy ML: A Practical
          Guide to Machine Learning with Differential Privacy",
          https://arxiv.org/abs/2303.00654, Sec 5.6.)
        max_examples_per_user: If the data set is constructed to cap the maximum
          number of examples each user contributes, provide this argument to also
          print a user-level DP guarantee.
        accountant_type: The privacy accountant for computing epsilon. Since the
          current approach for computing user-level privacy when using PLD
          accountant can sometimes be overly pessimistic, this method does not
          provide user-level privacy guarantee for PLD accountant_type. This remains
          to be investigated and fixed (b/271341062).
  
      Returns:
        A str precisely articulating the privacy guarantee.
      """
  
      paragraph = f"""\
  DP-SGD performed over {number_of_examples} examples with {batch_size} \
  examples per iteration, noise multiplier {noise_multiplier} for {num_epochs} \
  epochs {'with' if used_microbatching else 'without'} microbatching"""
  
      if max_examples_per_user is None:
          paragraph += ", and no bound on number of examples per user."
      else:
          paragraph += f", and at most {max_examples_per_user} examples per user."
  
      paragraphs = [textwrap.fill(paragraph, width=80)]
  
      paragraphs.append(
          textwrap.fill(
              """\
  This privacy guarantee protects the release of all model checkpoints in \
  addition to the final model.""",
              width=80,
          )
      )
  
      paragraph = textwrap.fill(
          f"""\
  Example-level DP with add-or-remove-one adjacency at delta = {delta} computed \
  with {accountant_type.value} accounting:""",
          width=80,
      )
  
      example_eps_no_subsampling = _compute_dp_sgd_example_privacy(
          num_epochs,
          noise_multiplier,
          delta,
          used_microbatching,
          accountant_type=accountant_type,
      )
      example_eps_subsampling = _compute_dp_sgd_example_privacy(
          num_epochs,
          noise_multiplier,
          delta,
          used_microbatching,
          poisson_subsampling_probability=batch_size
          / number_of_examples,
          accountant_type=accountant_type,
      )
  
      paragraph += f"""
      Epsilon with each example occurring once per epoch:  \
  {example_eps_no_subsampling:12.3f}
      Epsilon assuming Poisson sampling (*):               \
  {example_eps_subsampling:12.3f}"""
  
      paragraphs.append(paragraph)
  
      inf_user_eps = False
      if max_examples_per_user is None:
          paragraphs.append(
              textwrap.fill(
                  """\
  No user-level privacy guarantee is possible without a bound on the number of \
  examples per user.""",
                  width=80,
              )
          )
      elif accountant_type == AccountantType.PLD:
          # TODO(b/271341062): Add User level DP support for PLD.
          paragraphs.append(
              textwrap.fill(
                  """\
  User-level DP epsilon computation is not supported for PLD accounting at this \
  time. Use RDP accounting to obtain user-level DP guarantees.""",
                  width=80,
              )
          )
      else:  # Case: max_examples_per_user is not None and accountant_type is RDP
          user_eps_no_subsampling = _compute_dp_sgd_user_privacy(
              num_epochs,
              noise_multiplier,
              delta,
              max_examples_per_user,
              used_microbatching,
              accountant_type=accountant_type,
          )
          user_eps_subsampling = _compute_dp_sgd_user_privacy(
              num_epochs,
              noise_multiplier,
              delta,
              max_examples_per_user,
              used_microbatching,
              poisson_subsampling_probability=batch_size
              / number_of_examples,
              accountant_type=accountant_type,
          )
          if math.isinf(user_eps_no_subsampling):
              user_eps_no_subsampling_str = "    inf (**)"
              inf_user_eps = True
          else:
              user_eps_no_subsampling_str = (
                  f"{user_eps_no_subsampling:12.3f}"
              )
          if math.isinf(user_eps_subsampling):
              user_eps_subsampling_str = "    inf (**)"
              inf_user_eps = True
          else:
              user_eps_subsampling_str = f"{user_eps_subsampling:12.3f}"
  
          paragraph = textwrap.fill(
              f"""\
  User-level DP with add-or-remove-one adjacency at delta = {delta} computed \
  using {accountant_type.value} accounting and group privacy:""",
              width=80,
          )
          paragraph += f"""
      Epsilon with each example occurring once per epoch:  \
  {user_eps_no_subsampling_str}
      Epsilon assuming Poisson sampling (*):               \
  {user_eps_subsampling_str}"""
  
          paragraphs.append(paragraph)
  
      paragraphs.append(
          textwrap.fill(
              """\
  (*) Poisson sampling is not usually done in training pipelines, but assuming \
  that the data was randomly shuffled, it is believed that the actual epsilon \
  should be closer to this value than the conservative assumption of an \
  arbitrary data order.""",
              width=80,
          )
      )
  
      if inf_user_eps:
          paragraphs.append(
              textwrap.fill(
                  """\
  (**) A finite example-level epsilon implies a finite user-level epsilon at any \
  `max_examples_per_user`, but because conversion from example-level to user-\
  level DP is not exact, it is possible for the upper bound on the user-level \
  epsilon to still be infinite.""",
                  width=80,
              )
          )
  
      return "\n\n".join(paragraphs) + "\n"
  
file_path: privacy/tensorflow_privacy/privacy/analysis/compute_dp_sgd_privacy_lib.py
imports: import enum
  import functools
  import math
  import textwrap
  from typing import Optional
  from absl import app
  from absl import logging
  import dp_accounting
  from scipy import optimize
label_desc: Use image node_id 4 for calling a global function with example usage: compute_dp_sgd_privacy_statement(number_of_examples, batch_size, num_epochs, noise_multiplier, delta, used_microbatching, max_examples_per_user, accountant_type) and returns: unknown