Source code for synthpriv.privacy.accountant

"""Privacy accountant.

In phase 2 the real epsilon is computed by Opacus (RDP) during ``fit`` of the
``dp-gan`` generator and recorded here; the report shows that value, never a
configured target.
"""

from __future__ import annotations

from typing import Any

from synthpriv.privacy.mechanisms import PrivacyMechanism


[docs] class PrivacyAccountant: """Translates noise configuration into a real accumulated epsilon.""" def __init__(self, mechanism: PrivacyMechanism): self.mechanism = mechanism self._effective_epsilon: float | None = None
[docs] def set_effective_epsilon(self, epsilon: float) -> None: """Record the epsilon measured by the DP generator after ``fit``.""" self._effective_epsilon = float(epsilon)
[docs] def get_epsilon(self) -> float | None: """Effective epsilon (``None`` if there is no formal guarantee or it was not measured).""" if not self.mechanism.is_dp: return None return self._effective_epsilon
[docs] def report(self) -> dict[str, Any]: """Summary of the guarantee state for the report.""" return { "mechanism": self.mechanism.name, "dp": self.mechanism.is_dp, "effective_epsilon": self.get_epsilon(), "delta": getattr(self.mechanism, "delta", None), "noise_multiplier": getattr(self.mechanism, "used_noise_multiplier", None), "explanation": ( "" if self.get_epsilon() is not None else "No effective epsilon measured (non-DP mechanism or not trained)." ), }