Solution
Banasree answered on
Nov 12 2022
Privacy budget accountant for differential privacy
1. from numbers import Integral
import numpy as np
from diffprivlib.utils import Budget, BudgetE
o
from diffprivlib.validation import check_epsilon_delta
class BudgetAccountant:
2. _default = None
def __init__(self, epsilon=float("inf"), delta=1.0, slack=0.0, spent_budget=None):
check_epsilon_delta(epsilon, delta)
self.__epsilon = epsilon
self.__min_epsilon = 0 if epsilon == float("inf") else epsilon * 1e-14
self.__delta = delta
self.__spent_budget = []
self.slack = slack
if spent_budget is not None:
if not isinstance(spent_budget, list):
raise TypeE
or("spent_budget must be a list")
for _epsilon, _delta in spent_budget:
self.spend(_epsilon, _delta)
def __repr__(self, n_budget_max=5):
params = []
if self.epsilon != float("inf"):
params.append(f"epsilon={self.epsilon}")
if self.delta != 1:
params.append(f"delta={self.delta}")
if self.slack > 0:
params.append(f"slack={self.slack}")
if self.spent_budget:
if len(self.spent_budget) > n_budget_max:
params.append("spent_budget=" + str(self.spent_budget[:n_budget_max] + ["..."]).replace("'", ""))
else:
params.append("spent_budget=" + str(self.spent_budget))
return "BudgetAccountant(" + ", ".join(params) + ")"
def __enter__(self):
self.old_default = self.pop_default()
self.set_default()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.pop_default()
if self.old_default is not None:
self.old_default.set_default()
del self.old_default
def __len__(self):
return len(self.spent_budget)
@property
def slack(self):
"""Slack parameter for composition.
"""
return self.__slack
@slack.sette
def slack(self, slack):
if not 0 <= slack <= self.delta:
raise ValueE
or(f"Slack must be between 0 and delta ({self.delta}), inclusive. Got {slack}.")
epsilon_spent, delta_spent = self.total(slack=slack)
if self.epsilon < epsilon_spent or self.delta < delta_spent:
raise BudgetE
or(f"Privacy budget will be exceeded by changing slack to {slack}.")
self.__slack = slack
@property
def spent_budget(self):
return self.__spent_budget.copy()
@property
def epsilon(self):
"""Epsilon privacy ceiling of the accountant.
"""
return self.__epsilon
@property
def delta(self):
"""Delta privacy ceiling of the accountant.
"""
return self.__delta
[def total(self, spent_budget=None, slack=None):
3. if spent_budget is None:
spent_budget = self.spent_budget
else:
for epsilon, delta in spent_budget:
check_epsilon_delta(epsilon, delta)
if slack is None:
slack = self.slack
elif not 0 <= slack <= self.delta:
raise ValueE
or(f"Slack must be between 0 and delta ({self.delta}), inclusive. Got {slack}.")
epsilon_sum, epsilon_exp_sum, epsilon_sq_sum = 0, 0, 0
for epsilon, _ in spent_budget:
epsilon_sum += epsilon
epsilon_exp_sum += (1 - np.exp(-epsilon)) * epsilon / (1 + np.exp(-epsilon))
epsilon_sq_sum += epsilon ** 2
total_epsilon_naive = epsilon_sum
total_delta = self.__total_delta_safe(spent_budget, slack)
if slack == 0:
return Budget(total_epsilon_naive, total_delta)
total_epsilon_drv = epsilon_exp_sum + np.sqrt(2 * epsilon_sq_sum * np.log(1 / slack))
total_epsilon_kov = epsilon_exp_sum + np.sqrt(2 * epsilon_sq_sum *
np.log(np.exp(1) + np.sqrt(epsilon_sq_sum) / slack))
return Budget(min(total_epsilon_naive, total_epsilon_drv, total_epsilon_kov), total_delta)
def check(self, epsilon, delta):
4. check_epsilon_delta(epsilon, delta)
if self.epsilon == float("inf") and self.delta == 1:
return True
if 0 < epsilon < self.__min_epsilon:
raise ValueE
or(f"Epsilon must be at least {self.__min_epsilon} if...