Questions or feedback?

Fully Adaptive Composition and Odometers#

Where adaptive composition allows for queries to be chosen adaptively, fully adaptive composition also allows for the privacy loss of queries to be chosen adaptively. The API for fully adaptive composition matches that of adaptive composition, but drops the d_mids argument, as these will be chosen as you go.

>>> odom_fully_adaptive_comp = (
...     dp.c.make_fully_adaptive_composition(
...         input_domain=dp.vector_domain(
...             dp.atom_domain(T=int)
...         ),
...         input_metric=dp.symmetric_distance(),
...         output_measure=dp.max_divergence(),
...     )
... )
odom_fully_adaptive_comp <- make_fully_adaptive_composition(
  input_domain = vector_domain(atom_domain(.T = i32)),
  input_metric = symmetric_distance(),
  output_measure = max_divergence()
)

When the adaptive composition odometer (odom_fully_adaptive_comp) is invoked, it returns an odometer queryable.

>>> int_dataset = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> qbl_fully_adaptive_comp = odom_fully_adaptive_comp(
...     int_dataset
... )
int_dataset <- c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L)
qbl_fully_adaptive_comp <- odom_fully_adaptive_comp(arg = int_dataset)

You can check the privacy loss over all queries submitted to the queryable at any time. Since no queries have been submitted yet, the privacy loss is 0.

>>> qbl_fully_adaptive_comp.privacy_loss(1)
0.0
qbl_fully_adaptive_comp(d_in = 1L)
# 0.0

Similarly as before, we now interactively submit queries to estimate the sum and count:

>>> input_space = (
...     dp.vector_domain(dp.atom_domain(T=int)),
...     dp.symmetric_distance(),
... )
>>> meas_count = (
...     input_space
...     >> dp.t.then_count()
...     >> dp.m.then_laplace(scale=1.0)
... )
>>> meas_sum = (
...     input_space
...     >> dp.t.then_clamp((0, 10))
...     >> dp.t.then_sum()
...     >> dp.m.then_laplace(scale=5.0)
... )
>>> print("dp sum:", qbl_fully_adaptive_comp(meas_sum))
dp sum: ...
>>> print("dp count:", qbl_fully_adaptive_comp(meas_count))
dp count: ...
qbl_fully_adaptive_comp(query = meas_sum)
# 56
qbl_fully_adaptive_comp(query = meas_count)
# 10

Now that we have submitted two queries, we can see that the privacy loss has increased commensurately:

>>> qbl_fully_adaptive_comp.privacy_loss(1)
3.0
qbl_fully_adaptive_comp(d_in = 1L)
# 3.0