`` - ``FixedSmoothedMaxDivergence`` - :func:`opendp.combinators.make_pureDP_to_fixed_approxDP` * - ``MaxDivergence`` - ``ZeroConcentratedDivergence`` - :func:`opendp.combinators.make_pureDP_to_zCDP` * - ``ZeroConcentratedDivergence`` - ``SmoothedMaxDivergence`` - :func:`opendp.combinators.make_zCDP_to_approxDP` * - ``SmoothedMaxDivergence`` - ``FixedSmoothedMaxDivergence`` - :func:`opendp.combinators.make_fix_delta` :func:`opendp.combinators.make_pureDP_to_fixed_approxDP` is used for casting an output measure from ``MaxDivergence`` to ``FixedSmoothedMaxDivergence``. This is useful if you want to compose pure-DP measurements with approximate-DP measurements. .. doctest:: >>> from opendp.measurements import then_base_laplace >>> from opendp.combinators import make_pureDP_to_fixed_approxDP >>> from opendp.domains import atom_domain >>> from opendp.metrics import absolute_distance >>> input_space = atom_domain(T=float), absolute_distance(T=float) >>> meas_pureDP = input_space >> then_base_laplace(scale=10.) >>> # convert the output measure to `FixedSmoothedMaxDivergence` >>> meas_fixed_approxDP = make_pureDP_to_fixed_approxDP(meas_pureDP) ... >>> # FixedSmoothedMaxDivergence distances are (ε, δ) tuples >>> meas_fixed_approxDP.map(d_in=1.) (0.1, 0.0) Similarly, :func:`opendp.combinators.make_pureDP_to_zCDP` is used for casting an output measure from ``MaxDivergence`` to ``ZeroConcentratedDivergence``. :func:`opendp.combinators.make_zCDP_to_approxDP` is used for casting an output measure from ``ZeroConcentratedDivergence`` to ``SmoothedMaxDivergence``. .. doctest:: >>> from opendp.measurements import then_base_gaussian >>> from opendp.combinators import make_zCDP_to_approxDP >>> meas_zCDP = input_space >> then_base_gaussian(scale=0.5) >>> # convert the output measure to `SmoothedMaxDivergence` >>> meas_approxDP = make_zCDP_to_approxDP(meas_zCDP) ... >>> # SmoothedMaxDivergence distances are ε(δ) curves >>> curve = meas_approxDP.map(d_in=1.) >>> curve.epsilon(delta=1e-6) 11.688596249354896 :func:`opendp.combinators.make_fix_delta` changes the output measure from ``SmoothedMaxDivergence`` to ``FixedSmoothedMaxDivergence``. It fixes the delta parameter in the curve, so that the resulting measurement can be composed with other ``FixedSmoothedMaxDivergence`` measurements. .. doctest:: >>> from opendp.combinators import make_fix_delta >>> # convert the output measure to `FixedSmoothedMaxDivergence` >>> meas_fixed_approxDP = make_fix_delta(meas_approxDP, delta=1e-8) ... >>> # FixedSmoothedMaxDivergence distances are (ε, δ) tuples >>> meas_fixed_approxDP.map(d_in=1.) (13.3861046488579, 1e-08) These last two combinators allow you to convert output distances in terms of ρ-zCDP to ε(δ)-approxDP, and then to (ε, δ)-approxDP. Amplification ------------- If your dataset is a simple sample from a larger population, you can make the privacy relation more permissive by wrapping your measurement with a privacy amplification combinator: :func:`opendp.combinators.make_population_amplification`. .. note:: The amplifier requires a looser trust model, as the population size can be set arbitrarily. .. doctest:: >>> from opendp.mod import enable_features >>> enable_features("honest-but-curious") In order to demonstrate this API, we'll first create a measurement with a sized input domain. The resulting measurement expects the size of the input dataset to be 10. .. doctest:: >>> input_space = dp.vector_domain(dp.atom_domain(bounds=(0., 10.)), size=10), dp.symmetric_distance() >>> meas = input_space >> dp.t.then_mean() >> dp.m.then_laplace(scale=0.5) >>> print("standard mean:", meas([1.] * 10)) # -> 1.03 # doctest: +ELLIPSIS standard mean: ... We can now use the amplification combinator to construct an amplified measurement. The function on the amplified measurement is identical to the standard measurement. .. doctest:: >>> from opendp.combinators import make_population_amplification >>> amplified = make_population_amplification(meas, population_size=100) >>> print("amplified mean:", amplified([1.] * 10)) # -> .97 # doctest: +ELLIPSIS amplified mean: ... The privacy relation on the amplified measurement takes into account that the input dataset of size 10 is a simple sample of individuals from a theoretical larger dataset that captures the entire population, with 100 rows. .. doctest:: >>> # Where we once had a privacy utilization of ~2 epsilon... >>> assert meas.check(2, 2. + 1e-6) ... >>> # ...we now have a privacy utilization of ~.4941 epsilon. >>> assert amplified.check(2, .4941) The efficacy of this combinator improves as n gets larger.