def total(self, spent_budget=None, slack=None): """Returns the total current privacy spend. `spent_budget` and `slack` can be specified as parameters, otherwise the class values will be used. Parameters ---------- spent_budget : list of tuples of the form (epsilon, delta), optional List of tuples of budget spends. If not provided, the accountant's spends will be used. slack : float, optional Slack in delta for composition. If not provided, the accountant's slack will be used. Returns ------- epsilon : float Total epsilon spend. delta : float Total delta spend. """ 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 ValueError( "Slack must be between 0 and delta ({}), inclusive. Got {}.". format(self.delta, 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 __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 TypeError("spent_budget must be a list") for _epsilon, _delta in spent_budget: self.spend(_epsilon, _delta)
def test_real_inputs(self): with self.assertRaises(TypeError): check_epsilon_delta("1", "0") with self.assertRaises(TypeError): check_epsilon_delta(complex(1, 0.5), 0) with self.assertRaises(TypeError): check_epsilon_delta([1], [0]) self.assertIsNone(check_epsilon_delta(1, 0)) self.assertIsNone(check_epsilon_delta(1.0, 0.0))
def check(self, epsilon, delta): """Checks if the provided (epsilon,delta) can be spent without exceeding the accountant's budget ceiling. Parameters ---------- epsilon : float Epsilon budget spend to check. delta : float Delta budget spend to check. Returns ------- bool True if the budget can be spent, otherwise a :class:`.BudgetError` is raised. Raises ------ BudgetError If the specified budget spend will result in the budget ceiling being exceeded. """ check_epsilon_delta(epsilon, delta) if self.epsilon == float("inf") and self.delta == 1: return True if 0 < epsilon < self.__min_epsilon: raise ValueError( "Epsilon must be at least {} if non-zero, got {}.".format( self.__min_epsilon, epsilon)) spent_budget = self.spent_budget + [(epsilon, delta)] if Budget(self.epsilon, self.delta) >= self.total(spent_budget=spent_budget): return True raise BudgetError( "Privacy spend of ({},{}) not permissible; will exceed remaining privacy budget. " "Use {}.{}() to check remaining budget.".format( epsilon, delta, self.__class__.__name__, self.remaining.__name__))
def __new__(cls, epsilon, delta): check_epsilon_delta(epsilon, delta, allow_zero=True) return tuple.__new__(cls, (epsilon, delta))
def __new__(cls, epsilon, delta): from diffprivlib.validation import check_epsilon_delta check_epsilon_delta(epsilon, delta, allow_zero=True) return tuple.__new__(cls, (epsilon, delta))
def test_max_eps_delt(self): self.assertIsNone(check_epsilon_delta(float("inf"), 1))
def test_wrong_delta(self): with self.assertRaises(ValueError): check_epsilon_delta(0, -1) with self.assertRaises(ValueError): check_epsilon_delta(0, 1.1)
def test_neg_eps(self): with self.assertRaises(ValueError): check_epsilon_delta(-1, 0) with self.assertRaises(ValueError): check_epsilon_delta(-1e-100, 0)
def test_all_zero(self): with self.assertRaises(ValueError): check_epsilon_delta(0, 0) with self.assertRaises(ValueError): check_epsilon_delta(0.0, 0.0)