| Title: | Parsimonious Noise Perturbation for Magnitude Tables |
|---|---|
| Description: | Protects magnitude tables, such as tables of enterprise turnover, by multiplying each total by a Gaussian noise combining a dominance-driven component and a general-purpose one, governed by three parameters only. Information loss and disclosure risks for three attack scenarios (external inference, internal inference and differencing) are available in closed form, so that calibration requires neither simulation nor re-estimation on the data. The package guides that calibration step by step, from the differencing noise to the dominance parameters, with decision tables and risk-utility plots, applies the mechanism to an aggregated table using SHA-512 hashed random keys for consistency over time, and reports the risk and utility actually achieved. The method is described in Jamme (2027) <doi:10.1007/978-3-032-37883-5_9>. |
| Authors: | Julien Jamme [aut, cre] (ORCID: <https://orcid.org/0009-0009-9054-7053>), Institut national de la statistique et des études économiques [cph] |
| Maintainer: | Julien Jamme <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.2.0 |
| Built: | 2026-10-15 20:41:32 UTC |
| Source: | https://github.com/cran/dominoise |
Upper bound L(rho) = q * sqrt(rho^(2n) sigma_nu^2 + sigma_eps^2) of the
level-level confidence interval [-L(rho), L(rho)] of Z,
with q the (1+level)/2 quantile of the standard normal. The
interval is symmetric, so this single value gives both bounds.
assess_loss_ci(rho, sigma_nu, sigma_eps, n, level = 0.95)assess_loss_ci(rho, sigma_nu, sigma_eps, n, level = 0.95)
rho |
Dominance share X1/Y in (0,1]. Recycled. |
sigma_nu, sigma_eps, n
|
Mechanism parameters. Recycled. |
level |
Confidence level (default 0.95). |
The upper bound L(rho) as a relative quantity.
dominoise-package paper's Definition 4
assess_loss_ci(rho = 1, sigma_nu = 0.3, sigma_eps = 0.03, n = 6)assess_loss_ci(rho = 1, sigma_nu = 0.3, sigma_eps = 0.03, n = 6)
E(|Z| | P = rho) = sqrt(2 (rho^(2n) sigma_nu^2 + sigma_eps^2) / pi):
the average relative perturbation undergone by
a cell of dominance rho. Contrary to the differencing step – where letting
rho -> 0 makes the sigma_nu term vanish – the sigma_nu contribution is kept
in full here.
assess_loss_expectation(rho, sigma_nu, sigma_eps, n)assess_loss_expectation(rho, sigma_nu, sigma_eps, n)
rho |
Dominance share X1/Y in (0,1]. Recycled. |
sigma_nu, sigma_eps, n
|
Mechanism parameters. Recycled. |
E(|Z| | rho) as a relative quantity (multiply by 100 for percent).
dominoise-package paper's proposition 3
assess_loss_expectation(rho = 1, sigma_nu = 0.3, sigma_eps = 0.03, n = 6)assess_loss_expectation(rho = 1, sigma_nu = 0.3, sigma_eps = 0.03, n = 6)
Compute the upper bound of the differencing risk.
assess_risk_diff(sigma_eps, beta)assess_risk_diff(sigma_eps, beta)
sigma_eps |
double |
beta |
double |
A numeric vector: the upper bound of the differencing risk,
vectorised over sigma_eps and beta.
dominoise-package paper's proposition 7
assess_risk_diff(sigma_eps = 0.1, beta = 0.2)assess_risk_diff(sigma_eps = 0.1, beta = 0.2)
For each cell, evaluates whether the attack of a given scenario would in fact
have succeeded on the realised perturbation – scenario I:
|Y' - X1| / X1 < beta; scenario II: |(Y' - X2) - X1| / X1 < beta – and
compares the observed success rate with the theoretical probability
mu(rho) averaged over the table. The two should agree: the realised rate is
one draw from the probability the mechanism guarantees.
assess_risk_empirical(x, scenario = c("I", "II"), beta = NULL, by = NULL)assess_risk_empirical(x, scenario = c("I", "II"), beta = NULL, by = NULL)
x |
A table returned by |
scenario |
|
beta |
Accuracy threshold. Defaults to the matching policy of the parameter object. |
by |
Optional column name(s) to break the summary down by. |
Scenario II requires the x2 column to have been declared in pm_perturb(),
which adds the rho2 share the theoretical measure needs.
The differencing scenario is not assessed here: it bears on pairs of cells,
not on single cells, and is controlled a priori by the upper bound of the
metric.
A data.frame with the number of cells, the observed success rate
(in percent), the mean theoretical risk, and the maximum theoretical risk.
dominoise-package paper's proposition 7
set.seed(123) para <- suppressMessages( pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) ) tab <- data.frame(turnover = runif(500, 100, 1000), ck = runif(500)) tab$x1 <- tab$turnover * runif(500, 0.2, 1) tab$x2 <- (tab$turnover - tab$x1) * runif(500) res <- pm_perturb(tab, "turnover", "x1", "ck", para, x2 = "x2") assess_risk_empirical(res, scenario = "I") assess_risk_empirical(res, scenario = "II")set.seed(123) para <- suppressMessages( pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) ) tab <- data.frame(turnover = runif(500, 100, 1000), ck = runif(500)) tab$x1 <- tab$turnover * runif(500, 0.2, 1) tab$x2 <- (tab$turnover - tab$x1) * runif(500) res <- pm_perturb(tab, "turnover", "x1", "ck", para, x2 = "x2") assess_risk_empirical(res, scenario = "I") assess_risk_empirical(res, scenario = "II")
Probability that an external attacker infers the dominant contribution X1 to
within +/- beta :
mu_I(rho) = F_Z((1+beta)rho - 1) - F_Z((1-beta)rho - 1), with Z the
relative loss at dominance rho.
assess_risk_I(rho, sigma_nu, sigma_eps, n, beta)assess_risk_I(rho, sigma_nu, sigma_eps, n, beta)
rho |
Dominance share X1/Y in (0,1]. Recycled. |
sigma_nu, sigma_eps, n
|
Mechanism parameters. Recycled. |
beta |
Accuracy threshold of the inference. |
mu_I(rho), vectorised.
dominoise-package paper's proposition 5
assess_risk_I(rho = 0.85, sigma_nu = 0.3, sigma_eps = 0.03, n = 6, beta = 0.2)assess_risk_I(rho = 0.85, sigma_nu = 0.3, sigma_eps = 0.03, n = 6, beta = 0.2)
Probability that an insider contributing X2 to the aggregate infers the
dominant contribution X1 to within +/- beta, by subtracting their own
contribution from the disseminated total :
mu_II(rho, rho2) = F_Z((1+beta)rho + rho2 - 1) - F_Z((1-beta)rho + rho2 - 1),
with Z the relative loss at dominance rho.
assess_risk_II(rho, rho2, sigma_nu, sigma_eps, n, beta)assess_risk_II(rho, rho2, sigma_nu, sigma_eps, n, beta)
rho |
Share of the largest contribution, X1/Y, in (0,1]. Recycled. |
rho2 |
Share of the second contribution, X2/Y. Recycled. |
sigma_nu, sigma_eps, n
|
Mechanism parameters. Recycled. |
beta |
Accuracy threshold of the inference. |
The worst case (IIa) has the two largest contributors sharing the whole cell
(rho + rho2 = 1); the relaxed case (IIb) leaves a residual share to the
other contributors, typically rho + rho2 = 0.95.
mu_II(rho, rho2), vectorised.
dominoise-package paper's proposition 5
# worst case IIa at rho = 0.5 assess_risk_II(0.5, 0.5, sigma_nu = 0.4, sigma_eps = 0.031, n = 4, beta = 0.1)# worst case IIa at rho = 0.5 assess_risk_II(0.5, 0.5, sigma_nu = 0.4, sigma_eps = 0.031, n = 4, beta = 0.1)
Measures the perturbation actually undergone by the table, and compares it with the theoretical expectation evaluated at each cell's own dominance. A close match is the natural consistency check: the mechanism is analytical, so the realised loss should track the predicted one.
assess_utility_empirical(x, by = NULL, thresholds = c(5, 10, 20))assess_utility_empirical(x, by = NULL, thresholds = c(5, 10, 20))
x |
A table returned by |
by |
Optional column name(s) to break the summary down by (e.g. a publication stratum, or a dominance band built beforehand). |
thresholds |
Relative deviations (in percent) whose exceedance rate is reported. |
A data.frame: number of cells, mean and median absolute relative
deviation, quantiles, maximum, relative RMSE, exceedance rates, and the
theoretical mean absolute loss averaged over the observed dominance.
dominoise-package paper's proposition 3
set.seed(123) para <- suppressMessages( pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) ) tab <- data.frame(turnover = runif(500, 100, 1000), ck = runif(500)) tab$x1 <- tab$turnover * runif(500, 0.2, 1) tab$x2 <- (tab$turnover - tab$x1) * runif(500) res <- pm_perturb(tab, "turnover", "x1", "ck", para, x2 = "x2") assess_utility_empirical(res)set.seed(123) para <- suppressMessages( pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) ) tab <- data.frame(turnover = runif(500, 100, 1000), ck = runif(500)) tab$x1 <- tab$turnover * runif(500, 0.2, 1) tab$x2 <- (tab$turnover - tab$x1) * runif(500) res <- pm_perturb(tab, "turnover", "x1", "ck", para, x2 = "x2") assess_utility_empirical(res)
Draws the risk-utility frontier of the differencing step: the level risk ceiling tau
(guaranteed maximum differencing risk) against the relative loss (Z) level it costs
(either expectation of |Z| or upper bound of the confidence interval of it),
one curve per beta.
## S3 method for class 'pm_calib_diff' plot(x, loss = c("CI", "EZ"), ...)## S3 method for class 'pm_calib_diff' plot(x, loss = c("CI", "EZ"), ...)
x |
A |
loss |
One of |
... |
Ignored, for compatibility with the |
A ggplot object.
plot(pm_calib_diff())plot(pm_calib_diff())
Thin dispatcher over the three calibration plots.
## S3 method for class 'pm_calib_dominance' plot(x, type = c("tradeoff", "profile", "worst"), ...)## S3 method for class 'pm_calib_dominance' plot(x, type = c("tradeoff", "profile", "worst"), ...)
x |
A |
type |
|
... |
Passed on to the underlying plotting function. |
A ggplot object.
grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2) plot(grid) plot(grid, type = "profile")grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2) plot(grid) plot(grid, type = "profile")
sigma_epsilon)Calibration of the differencing noise (sigma_epsilon)
pm_calib_diff(params = NULL, beta = NULL, tau = NULL, level = 0.95)pm_calib_diff(params = NULL, beta = NULL, tau = NULL, level = 0.95)
params |
object |
beta |
real vector of |
tau |
real vector of |
level |
confidence level for the confidence interval of the relative loss |
By default, the function returns the results for some beta and tau values beta in (0.05, 0.1, 0.15, 0.2, 0.25) and tau in (0.5, 0.55, 0.6, ..., 0.90, 0.95)
A data.frame of class pm_calib_diff, one row per (beta, tau)
couple, with columns beta, tau, sigma_eps, and the loss floor it
implies at rho -> 0: EZ (mean absolute loss) and CI (upper bound of
the level confidence interval), both in percent. The confidence level is
stored in the level attribute.
# default behaviour pm_calib_diff()# default behaviour pm_calib_diff()
Theoretical, data-free. For every candidate (sigma_nu, n, beta, sigma_eps),
evaluates the scenario-I risk over an internal grid of dominance levels
rho, keeps its worst case (max over rho), and reports the maximum
information loss (reached at rho = 1, hence set by sigma_nu alone). The
returned table is the decision surface of step 2: feed it to plot() for the
risk heat-map, to pm_suggest_n() for the largest admissible n, then lock
the choice with pm_commit_dominance().
pm_calib_dominance( params = NULL, sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, level = 0.95, rho = NULL )pm_calib_dominance( params = NULL, sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, level = 0.95, rho = NULL )
params |
Optional |
sigma_nu, n
|
Numeric vectors of candidate values. Default to
|
beta |
Accuracy threshold(s) of scenario I. Default to the |
sigma_eps |
Fixed differencing noise. Default to
|
level |
Confidence level for the CI loss metric (default 0.95). |
rho |
Internal grid of dominance levels used to locate the worst case.
Default |
Like pm_calib_diff(), calling it with everything at NULL returns a
default exploration grid.
A data.frame of class pm_calib_dominance, one row per
(rho, sigma_nu, sigma_eps, n, beta), with columns risk (scenario-I
risk), EZ and CI (information loss, in percent). The confidence level
is stored in the level attribute. Use summary() for the worst case
over rho of each parameter combination.
# default exploration grid <- pm_calib_dominance() grid summary(grid) # at a committed sigma_eps para <- pm_commit_diff(pm_params()) grid <- pm_calib_dominance(para)# default exploration grid <- pm_calib_dominance() grid summary(grid) # at a committed sigma_eps para <- pm_commit_diff(pm_params()) grid <- pm_calib_dominance(para)
Once beta_diff and tau_diff are chosen (typically after exploring with
pm_calib_diff()), this fills sigma_eps in the pm_params object and
records the two policy values. It is the single place where step 1 mutates
params.
pm_commit_diff( params, beta = params$policy$diff$beta, tau = params$policy$diff$tau, level = 0.95 )pm_commit_diff( params, beta = params$policy$diff$beta, tau = params$policy$diff$tau, level = 0.95 )
params |
A |
beta, tau
|
The chosen threshold and ceiling. Default to the values
already stored in the |
level |
Confidence level used only for the informative message. |
The updated pm_params (returned invisibly).
parameters <- pm_params() # beta and tau already set in the pm_params object: parameters <- pm_commit_diff(parameters) parameters # if an another choice is preferred (after calibration search) parameters <- pm_commit_diff(parameters, beta = 0.1, tau = 0.9) parametersparameters <- pm_params() # beta and tau already set in the pm_params object: parameters <- pm_commit_diff(parameters) parameters # if an another choice is preferred (after calibration search) parameters <- pm_commit_diff(parameters, beta = 0.1, tau = 0.9) parameters
Closes calibration step 2: records the chosen sigma_nu and n, together
with the scenario-I policy (beta, tau), into the pm_params object. This
is the single place where step 2 mutates params.
pm_commit_dominance( params, sigma_nu, n, beta = NULL, tau = NULL, level = 0.95, rho = NULL )pm_commit_dominance( params, sigma_nu, n, beta = NULL, tau = NULL, level = 0.95, rho = NULL )
params |
A |
sigma_nu, n
|
The chosen values (single values). Recall the calibration
rule of step 2: keep the largest |
beta, tau
|
Scenario-I accuracy threshold and risk ceiling. Default to
the |
level |
Confidence level for the reported CI loss (default 0.95). |
rho |
Grid used to locate the worst case over rho.
Default |
Requires sigma_eps to be already set (step 1), since both the scenario-I
risk and the information loss depend on it. The function reports the
resulting worst-case risk over rho, where that worst case occurs, and the
range of the information loss – from its floor (rho -> 0, driven by
sigma_eps alone) to its ceiling (rho = 1, driven by sigma_nu). A warning
is raised when the worst-case risk exceeds tau: the values are still
recorded, the producer being free to accept the overshoot knowingly.
The updated pm_params, invisibly.
para <- pm_commit_diff(pm_params()) para <- pm_commit_dominance(para, sigma_nu = 0.3, n = 6) parapara <- pm_commit_diff(pm_params()) para <- pm_commit_dominance(para, sigma_nu = 0.3, n = 6) para
Implements Definitions 6-7 of the paper. From the cell key CK, the name of
the indicator and the aggregation operation, two distinct strings are built
– one per draw – and hashed with SHA-512. Each digest is mapped to a
uniform draw in ]0;1[, then turned into a Gaussian draw by quantile
inversion: nu from N(0, sigma_nu^2) and eps from N(0, sigma_eps^2).
pm_draws(ck, params, indicator, operation = "sum", key_digits = 9L)pm_draws(ck, params, indicator, operation = "sum", key_digits = 9L)
ck |
Numeric vector of cell keys in [0;1]. |
params |
A fully calibrated |
indicator |
Name of the indicator the aggregate is computed from
(e.g. |
operation |
Name of the aggregation (default |
key_digits |
Number of decimals used to turn the key into a string. Fixed for reproducibility; changing it changes every draw. |
Determinism, avalanche effect and uniformity of SHA-512
ensure that the same cell always receives the same perturbation, while draws
remain uncorrelated across indicators and between nu and eps.
A data.frame with columns ck_nu, ck_eps, nu, eps.
dominoise-package paper's proposition 8
para <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) pm_draws(c(0.12, 0.87), para, indicator = "turnover")para <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) pm_draws(c(0.12, 0.87), para, indicator = "turnover")
Create the perturbation-parameter object containing all the parameters of the noise.
pm_params( beta_dominance = 0.2, tau_dominance = 0.9, beta_prule = 0.1, tau_prule = 0.9, s_prule = 0.95, beta_diff = 0.05, tau_diff = 0.95, sigma_nu = NA_real_, sigma_eps = NA_real_, n = NA_real_ )pm_params( beta_dominance = 0.2, tau_dominance = 0.9, beta_prule = 0.1, tau_prule = 0.9, s_prule = 0.95, beta_diff = 0.05, tau_diff = 0.95, sigma_nu = NA_real_, sigma_eps = NA_real_, n = NA_real_ )
beta_dominance, tau_dominance
|
Accuracy threshold and risk ceiling for scenario I (dominance rule). Defaults to 0.2 / 0.9. |
beta_prule, tau_prule, s_prule
|
Threshold, ceiling and cumulated share of
the two largest contributors for scenario II (p%-rule). |
beta_diff, tau_diff
|
Threshold and ceiling for the differencing scenario. Defaults: 0.05 / 0.95. |
sigma_nu, sigma_eps, n
|
Mechanism parameters, filled in during
calibration. Left as |
An object of class pm_params: a list with two elements,
policy (sub-lists dominance, prule and diff, each holding the
accuracy threshold beta and the risk ceiling tau, plus s for prule)
and mechanism (sigma_nu, sigma_eps, n).
para <- pm_params() parapara <- pm_params() para
Applies the mechanism of Definition 2 to a table of sums:
Y' = Y (1 + rho^n nu + eps) with rho = X1 / Y. The draws are obtained
from the cell keys via pm_draws(), so the perturbation is reproducible:
re-running on the same cells and the same indicator returns the same values.
pm_perturb( data, total, x1, ck_var, params, indicator = NULL, operation = "sum", x2 = NULL, reduce_key = FALSE, key_digits = 9L )pm_perturb( data, total, x1, ck_var, params, indicator = NULL, operation = "sum", x2 = NULL, reduce_key = FALSE, key_digits = 9L )
data |
A |
total, x1
|
Column names (strings): the aggregate and the largest contribution, in the same unit. |
ck_var |
Column name of the aggregated cell key. |
params |
A fully calibrated |
indicator |
Name of the indicator; defaults to the |
operation |
Aggregation name entering the hash (default |
x2 |
Optional column name of the second largest contribution. When
given, the share |
reduce_key |
If |
key_digits |
Decimals used to stringify the key before hashing (default 9). |
The mechanism is defined for strictly positive totals. Cells with a non-positive total are left unperturbed and flagged, with a warning: being multiplicative, the noise protects neither zeros nor near-zero values.
data with added columns rho, rho2 (when x2 is given),
ck_nu, ck_eps, and the perturbed total named <total>_pert.
Calibration parameters and hashing settings are attached as the pm_meta
attribute.
para <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) tab <- data.frame(turnover = c(1000, 500), x1 = c(850, 120), ck = c(0.12, 0.87)) pm_perturb(tab, total = "turnover", x1 = "x1", ck_var = "ck", params = para)para <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) tab <- data.frame(turnover = c(1000, 500), x1 = c(850, 120), ck = c(0.12, 0.87)) pm_perturb(tab, total = "turnover", x1 = "x1", ck_var = "ck", params = para)
Plots the relative deviation actually undergone by each cell against its
dominance level, and overlays the theoretical envelope predicted before any
data were touched: the level-level confidence band of the relative loss
(Definition 4) and the mean absolute loss.
pm_plot_impact(x, level = 0.95, colour_by = NULL, alpha = 0.35, n_grid = 200)pm_plot_impact(x, level = 0.95, colour_by = NULL, alpha = 0.35, n_grid = 200)
x |
A table returned by |
level |
Confidence level of the band (default 0.95). |
colour_by |
Optional column name used to colour the points (e.g. a publication stratum). |
alpha |
Point transparency; lower it on large tables. |
n_grid |
Number of dominance values used to draw the envelope. |
The mechanism being analytical, the cloud of points should fill the band and straddle the mean lines. That agreement is the natural consistency check between what was promised at calibration time and what the table received.
A ggplot object.
dominoise-package paper's proposition 3
set.seed(123) N = 1000 params <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) rhos <- runif(N, 0, 1) tab <- data.frame(turnover = runif(N, 0,1000), ck = runif(N, 0, 1)) tab$x1 <- tab$turnover * rhos res <- pm_perturb(tab, "turnover", "x1", "ck", params) pm_plot_impact(res)set.seed(123) N = 1000 params <- pm_commit_dominance(pm_commit_diff(pm_params()), sigma_nu = 0.4, n = 4) rhos <- runif(N, 0, 1) tab <- data.frame(turnover = runif(N, 0,1000), ck = runif(N, 0, 1)) tab$x1 <- tab$turnover * rhos res <- pm_perturb(tab, "turnover", "x1", "ck", params) pm_plot_impact(res)
Reduces a calibration table to the worst case over rho of the disclosure
risk, at a fixed sigma_eps, and plots it against one of the two mechanism
parameters. Panels are split by scenario when several are present.
pm_plot_risk_max( x, x_axis = c("sigma_nu", "n"), sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, tau = NULL, mark_frontier = NULL, marks = NULL, thresholds = c(0.5, 0.8) )pm_plot_risk_max( x, x_axis = c("sigma_nu", "n"), sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, tau = NULL, mark_frontier = NULL, marks = NULL, thresholds = c(0.5, 0.8) )
x |
A calibration table (e.g. from |
x_axis |
Parameter on the x-axis: |
sigma_nu, n, beta, sigma_eps, scenario
|
Optional values to keep; |
tau |
Optional risk ceiling, drawn as an extra dashed line on top of
|
mark_frontier |
Whether to mark the largest admissible |
marks |
Values of the x-axis parameter highlighted with a point;
|
thresholds |
Risk levels drawn as dashed horizontal lines. |
With x_axis = "sigma_nu" (default) this reproduces the middle panel of
Figure 3 of the paper, generalised: the risk decreases with sigma_nu, one
curve per n.
With x_axis = "n" it is the view that accompanies pm_suggest_n(): the
risk increases monotonically with n, one curve per sigma_nu. Each
crossing of the ceiling tau is the n_max of its sigma_nu – the very
root that pm_suggest_n() solves for. Those points are overlaid when
mark_frontier allows it, computed by the same function so that the plot
and the table always agree.
A ggplot object.
pm_suggest_n(), plot.pm_calib_dominance().
# Figure 3 (middle panel): worst-case risk against sigma_nu grid <- pm_calib_dominance(sigma_nu = (2:100)/200, n = c(3, 6, 9, 12), beta = 0.2) pm_plot_risk_max(grid, marks = c(0.05, 0.1, 0.2, 0.3, 0.4, 0.5)) # Against n, with the frontier found by pm_suggest_n() grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2, sigma_nu = c(0.3, 0.4, 0.5), n = (5:60)/5) pm_plot_risk_max(grid, x_axis = "n", tau = 0.5)# Figure 3 (middle panel): worst-case risk against sigma_nu grid <- pm_calib_dominance(sigma_nu = (2:100)/200, n = c(3, 6, 9, 12), beta = 0.2) pm_plot_risk_max(grid, marks = c(0.05, 0.1, 0.2, 0.3, 0.4, 0.5)) # Against n, with the frontier found by pm_suggest_n() grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2, sigma_nu = c(0.3, 0.4, 0.5), n = (5:60)/5) pm_plot_risk_max(grid, x_axis = "n", tau = 0.5)
Reproduces Figure 2 of the paper, generalised: the disclosure risk against
the dominance level rho, one curve per shape parameter n, panels split by
sigma_nu (and by scenario when the table carries several).
pm_plot_risk_profile( x, sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, thresholds = c(0.5, 0.8) )pm_plot_risk_profile( x, sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, thresholds = c(0.5, 0.8) )
x |
A calibration table (e.g. from |
sigma_nu, n, beta, sigma_eps, scenario
|
Optional values to keep; |
thresholds |
Risk levels drawn as dashed horizontal lines. |
A ggplot object.
grid <- pm_calib_dominance(beta = c(0.1,0.2)) pm_plot_risk_profile(grid, sigma_nu = c(0.1, 0.2, 0.4, 0.5), beta = 0.2)grid <- pm_calib_dominance(beta = c(0.1,0.2)) pm_plot_risk_profile(grid, sigma_nu = c(0.1, 0.2, 0.4, 0.5), beta = 0.2)
Reproduces Figure 4 of the paper: for each (sigma_nu, n) the curve traces
the (information loss, risk) couple as rho runs over ]0;1]. Loss on the
x-axis, risk on the y-axis, colour by sigma_nu, panels by n, and open
symbols marking a few reference dominance levels.
pm_plot_tradeoff( x, loss = c("EZ", "CI"), sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, rho_marks = c(0.8, 0.9, 0.95), thresholds = c(0.5, 0.8) )pm_plot_tradeoff( x, loss = c("EZ", "CI"), sigma_nu = NULL, n = NULL, beta = NULL, sigma_eps = NULL, scenario = NULL, rho_marks = c(0.8, 0.9, 0.95), thresholds = c(0.5, 0.8) )
x |
A calibration table (e.g. from |
loss |
Loss metric on the x-axis: |
sigma_nu, n, beta, sigma_eps, scenario
|
Optional values to keep. |
rho_marks |
Dominance levels highlighted with a symbol. |
thresholds |
Risk levels drawn as dashed horizontal lines. |
Generalised on the choice of the risk metric only: pick the scenario with
scenario when the table carries several, since a single risk column can be
plotted at a time.
A ggplot object.
grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2) pm_plot_tradeoff(grid)grid <- pm_calib_dominance(sigma_eps = 0.031, beta = 0.2) pm_plot_tradeoff(grid)
sigma_eps guaranteeing the differencing-risk ceilingClosed-form inversion of the worst-case upper bound of the differencing risk.
pm_sigma_eps(beta, tau)pm_sigma_eps(beta, tau)
beta, tau
|
Numeric. Accuracy threshold and risk ceiling. |
A numeric vector of sigma_eps values, vectorised over
beta/tau.
dominoise-package (Proposition 7 of the paper).
pm_sigma_eps(beta = 0.05, tau = 0.95) pm_sigma_eps(beta = c(0.05, 0.1), tau = 0.9)pm_sigma_eps(beta = 0.05, tau = 0.95) pm_sigma_eps(beta = c(0.05, 0.1), tau = 0.9)
Implements the step-2 calibration rule. The worst-case scenario-I risk
increases with n, while the information loss decreases with n at every
rho < 1 and is unchanged at rho = 1. Both objectives are therefore
monotone and opposite in n: there is no interior optimum, and the best
choice is the upper edge of the admissible set,
n_max = sup{n : max_rho mu_I <= tau}. Because the risk is monotone, that
edge is found by root-finding rather than by a grid search.
pm_suggest_n( params = NULL, sigma_nu = NULL, beta = NULL, tau = NULL, sigma_eps = NULL, margin = 0, n_range = c(1, 30), integer = FALSE, level = 0.95, rho = NULL )pm_suggest_n( params = NULL, sigma_nu = NULL, beta = NULL, tau = NULL, sigma_eps = NULL, margin = 0, n_range = c(1, 30), integer = FALSE, level = 0.95, rho = NULL )
params |
Optional |
sigma_nu |
Numeric vector of candidate values. Default |
beta, tau
|
Scenario-I threshold and ceiling. Default to the |
sigma_eps |
Fixed differencing noise. Defaults to
|
margin |
Safety margin in [0,1): the effective ceiling is
|
n_range |
Search interval for |
integer |
If |
level |
Confidence level for the reported CI loss (default 0.95). |
rho |
Grid used to locate the worst case. Default |
The rule holds whatever the dominance profile of the table: since utility
improves at every rho, no weighting by the actual distribution of rho
could favour a smaller n.
Note this determines n given sigma_nu. Every point of the returned
frontier meets the ceiling exactly, so choosing among them is a pure utility
arbitrage – larger sigma_nu costs more at rho = 1 but spares cells of
intermediate dominance. The reported losses are there to settle it.
A data.frame with one row per sigma_nu: n_max,
risk_at_n_max, and the information loss at rho = 1 and at the dominance
threshold 1 - beta. n_max is NA when no n meets the ceiling (raise
sigma_nu), and the upper end of n_range when the whole range qualifies.
para <- pm_commit_diff(pm_params()) pm_suggest_n(para, sigma_nu = c(0.3, 0.4, 0.5))para <- pm_commit_diff(pm_params()) pm_suggest_n(para, sigma_nu = c(0.3, 0.4, 0.5))
Reduces the rho-resolved table to one row per parameter combination
(sigma_nu, sigma_eps, n, beta). For each, reports where the scenario-I risk
peaks and its value, and the range of the information loss: the minimum
(smallest rho of the grid) and the maximum (rho = 1), in both metrics –
expectation E|Z| and upper CI bound. The loss is monotone increasing in rho,
so these are read at the extreme rho rows of each group.
## S3 method for class 'pm_calib_dominance' summary(object, ...)## S3 method for class 'pm_calib_dominance' summary(object, ...)
object |
A |
... |
Ignored. |
A data.frame of class pm_calib_dominance_summary, with columns
sigma_nu, sigma_eps, n, beta, rho_at_max_risk, risk_max,
EZ_min, EZ_max, CI_min, CI_max (losses in percent).
grid <- pm_calib_dominance(sigma_nu = c(0.3, 0.4), n = c(3, 6), beta = 0.2) summary(grid)grid <- pm_calib_dominance(sigma_nu = c(0.3, 0.4), n = c(3, 6), beta = 0.2) summary(grid)