Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pipeline_dp/aggregate_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class MechanismType(Enum):
GAUSSIAN = 'Gaussian'
LAPLACE_THRESHOLDING = 'Laplace Thresholding'
GAUSSIAN_THRESHOLDING = 'Gaussian Thresholding'
EXPONENTIAL = 'Exponential'
GENERIC = 'Generic'

def to_noise_kind(self):
Expand Down
14 changes: 13 additions & 1 deletion pipeline_dp/budget_accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ def set_noise_standard_deviation(self, stddev: float):
self._noise_standard_deviation = stddev

def use_delta(self) -> bool:
return self.mechanism_type != agg_params.MechanismType.LAPLACE
return self.mechanism_type not in [
agg_params.MechanismType.LAPLACE,
agg_params.MechanismType.EXPONENTIAL
]

@property
def standard_deviation_is_set(self) -> bool:
Expand All @@ -118,6 +121,15 @@ class MechanismSpecInternal:
weight: float
mechanism_spec: MechanismSpec

def __post_init__(self):
mechanism_type = self.mechanism_spec.mechanism_type
if self.sensitivity != 1 and mechanism_type in [
agg_params.MechanismType.EXPONENTIAL,
agg_params.MechanismType.GENERIC
]:
raise ValueError(
f"Mechanism {mechanism_type} does not support sensitivity.")


Budget = collections.namedtuple("Budget", ["epsilon", "delta"])

Expand Down
37 changes: 31 additions & 6 deletions tests/budget_accounting_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,28 @@ def test_budget_scopes_no_parentscope(self):
self.assertEqual(budget1.eps, 1.0 / (1.0 + 0.5))
self.assertEqual(budget2.eps, 0.5 / (1.0 + 0.5))

def test_count(self):
def test_weights_count(self):
budget_accountant = NaiveBudgetAccountant(total_epsilon=1,
total_delta=1e-6)
budget1 = budget_accountant.request_budget(
mechanism_type=MechanismType.LAPLACE, weight=4)
budget2 = budget_accountant.request_budget(
mechanism_type=MechanismType.GAUSSIAN, weight=3, count=2)
budget3 = budget_accountant.request_budget(
mechanism_type=MechanismType.EXPONENTIAL, weight=2, count=5)
budget_accountant.compute_budgets()

self.assertEqual(budget1.eps, 0.4)
self.assertEqual(budget1.delta,
0) # Delta should be 0 if mechanism is Laplace.
# Total_weight = 4 + 3*2 + 2*5 = 20
# eps1 = total_epsilon*weight/total_weight = 1*4/20
self.assertEqual(budget1.eps, 0.2)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe write a formula, not trivial

self.assertEqual(budget1.delta, 0) # delta=0 for Laplace.

self.assertEqual(budget2.eps, 0.3)
self.assertEqual(budget2.eps, 0.15) # = 1*3/20
self.assertEqual(budget2.delta, 5e-7)

self.assertEqual(budget3.eps, 0.1) # = 1*2/20
self.assertEqual(budget3.delta, 0) # delta=0 for Exponential.

def test_two_calls_compute_budgets_raise_exception(self):
budget_accountant = NaiveBudgetAccountant(total_epsilon=1,
total_delta=1e-6)
Expand Down Expand Up @@ -467,7 +473,26 @@ class ComputeBudgetTestCase:
weight=8,
sensitivity=3),
],
expected_pipeline_noise_std=40.02)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we write/point to the formulas in the class definition?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we should write documentation on PLD accountant. In this case, there is no simple formula anyway :)

expected_pipeline_noise_std=40.02),
ComputeBudgetTestCase(
name="gaussian_exponential",
epsilon=1.0,
delta=1e-6,
mechanisms=[
ComputeBudgetMechanisms(
count=4,
expected_noise_std=1.295,
mechanism_type=MechanismType.EXPONENTIAL,
weight=4,
sensitivity=1),
ComputeBudgetMechanisms(
count=6,
expected_noise_std=10.356,
mechanism_type=MechanismType.GAUSSIAN,
weight=2,
sensitivity=4),
],
expected_pipeline_noise_std=5.178)
]

for case in testcases:
Expand Down
Loading