Transformation example#
Use make_user_transformation() to construct your own transformation.
Note
This requires a looser trust model, as we cannot verify any privacy or stability properties of user-defined functions.
>>> import opendp.prelude as dp
>>> dp.enable_features("honest-but-curious", "contrib")
enable_features("honest-but-curious", "contrib")
In this example, we mock the typical API of the OpenDP library to make a transformation that duplicates each record multiplicity times:
>>> def make_repeat(multiplicity):
... """Construct a Transformation that duplicates each record `multiplicity` times."""
... def function(arg: list[int]) -> list[int]:
... return arg * multiplicity
... def stability_map(d_in: int) -> int:
... return d_in * multiplicity
... return dp.t.make_user_transformation(
... input_domain=dp.vector_domain(
... dp.atom_domain(T=int)
... ),
... input_metric=dp.symmetric_distance(),
... output_domain=dp.vector_domain(
... dp.atom_domain(T=int)
... ),
... output_metric=dp.symmetric_distance(),
... function=function,
... stability_map=stability_map,
... )
...
make_repeat <- function(input_domain, input_metric, multiplicity) {
function_ <- function(arg) rep(arg, multiplicity)
stability_map <- function(d_in) d_in * multiplicity
make_user_transformation(
input_domain = input_domain,
input_metric = input_metric,
output_domain = input_domain,
output_metric = input_metric,
function_ = function_,
stability_map = stability_map
)
}
then_repeat <- to_then(make_repeat)
The resulting Transformation may be used interchangeably with those constructed via the library:
>>> trans = (
... (
... dp.vector_domain(dp.atom_domain(T=str)),
... dp.symmetric_distance(),
... )
... >> dp.t.then_cast_default(TOA=int)
... >> make_repeat(2)
... >> dp.t.then_clamp((1, 2))
... >> dp.t.then_sum()
... >> dp.m.then_laplace(1.0)
... )
>>> release = trans(["0", "1", "2", "3"])
>>> trans.map(1)
4.0
space <- c(
vector_domain(atom_domain(.T = String)),
symmetric_distance()
)
trans <- space |>
then_cast_default(.TOA = i32) |>
then_repeat(2L) |>
then_clamp(c(1L, 2L)) |>
then_sum() |>
then_laplace(1.)
release <- trans(arg = c("0", "1", "2", "3"))
trans(d_in = 1L)
The code snip may form a basis for you to create your own data transformations, and mix them into an OpenDP analysis.