Ejemplo n.º 1
0
def test_laplace_mechanism_confidence_interval():
    ci = LaplaceMechanism.confidence_interval(epsilon=0.1,
                                              sensitivity=1,
                                              confidence=0.95)

    # Exact CI computed using scipy.stats.laplace.ppf
    assert pytest.approx(ci, abs=0.001) == 29.9573

    # Validate the reverse holds
    epsilon = LaplaceMechanism.epsilon_for_confidence_interval(target_ci=ci,
                                                               sensitivity=1,
                                                               confidence=0.95)
    assert pytest.approx(epsilon, abs=0.001) == 0.1
Ejemplo n.º 2
0
 def epsilon_for_confidence_interval(self, *, target_ci, confidence=0.95):
     """Return epsilon for a desired confidence interval."""
     return LaplaceMechanism.epsilon_for_confidence_interval(
         target_ci=target_ci,
         sensitivity=(self.upper_bound - self.lower_bound),
         confidence=confidence,
     )
Ejemplo n.º 3
0
 def confidence_interval(self, *, epsilon, confidence=0.95):
     """Compute the two-sided confidence interval for the sum."""
     return LaplaceMechanism.confidence_interval(
         epsilon=epsilon,
         sensitivity=(self.upper_bound - self.lower_bound),
         confidence=confidence,
     )
Ejemplo n.º 4
0
    def execute(self, *, values: List[float], epsilon: float, quantile: float):
        """
        Computes the quantile of a list of values privately.

        Implemented using Report Noisy Max (Claim 3.9) of [Dwork and Roth].

        Args:
            values: Dataset
            epsilon: Privacy parameter
            quantile: Quantile to return (between 0 and 1)

        References:
            - Dwork, C., Roth, A., 2013. The Algorithmic Foundations of Differential Privacy. FNT in Theoretical Computer Science 9, 211–407. https://doi.org/10.1561/0400000042
        """
        N = len(values)

        sensitivity = self.max_individual_contribution

        def score(values, option):
            count = np.sum(values < option)
            return -np.abs(count - N * quantile)

        scores = [score(values, option) for option in self.options]
        noisy_scores = LaplaceMechanism.execute_batch(
            values=scores, epsilon=epsilon, sensitivity=sensitivity
        )
        max_idx = np.argmax(noisy_scores)
        return self.options[max_idx]
Ejemplo n.º 5
0
 def confidence_interval(self, *, epsilon: float, confidence: float = 0.95) -> float:
     """Return the confidence interval for each bar of the histogram."""
     return LaplaceMechanism.confidence_interval(
         epsilon=epsilon,
         sensitivity=self.max_individual_contribution,
         confidence=confidence,
     )
Ejemplo n.º 6
0
def test_private_histogram_helpers():
    op = PrivateHistogram(bins=[], max_individual_contribution=1)
    histogram_ci = op.confidence_interval(epsilon=1, confidence=0.95)
    laplace_ci = LaplaceMechanism.confidence_interval(
        epsilon=1, sensitivity=1, confidence=0.95
    )
    assert histogram_ci == laplace_ci
Ejemplo n.º 7
0
    def execute(self, *, queries: List[float], threshold: float, epsilon: float):
        """
        Args:
            queries: List of sensitivity-1 queries to choose from
            threshold: Threshold above which the first query will be returned
            epsilon: Privacy parameter

        Return:
            The index of the query that exceeds `threshold`.
        """
        noisy_threshold = threshold + LaplaceMechanism.execute(
            value=0, sensitivity=2, epsilon=epsilon
        )

        for idx, q in enumerate(queries):
            nu_i = LaplaceMechanism.execute(value=0, sensitivity=4, epsilon=epsilon)
            if q + nu_i >= noisy_threshold:
                return idx
        return -1
Ejemplo n.º 8
0
    def execute(self, *, values: List[float], epsilon: float) -> List[float]:
        """
        Computes the histogram of `values` privately.

        Values are clamped to the bound specified by ``bins``.

        Return:
            A list of private counts, one for each bin.
        """
        sensitivity = self.max_individual_contribution
        bins = np.sort(self.bins)
        values = np.clip(values, bins[0], bins[-1])
        counts, _ = np.histogram(values, bins=bins)
        noisy_counts = LaplaceMechanism.execute_batch(
            values=counts, epsilon=epsilon, sensitivity=sensitivity
        )
        return noisy_counts
Ejemplo n.º 9
0
    def execute(self, *, vectors: List[float], epsilon: float, delta: float) -> float:
        """
        Computes the mean of `vectors` privately using a clamped sum and
        exact count with the Laplace Mechanism.
        """

        lower_bound = self.lower_bound
        upper_bound = self.upper_bound

        clamped_vectors = np.array(
            [np.clip(v, lower_bound, upper_bound) for v in vectors]
        )

        exact_sum = np.sum(clamped_vectors, axis=0)

        sensitivity = (upper_bound - lower_bound) * self.k

        private_sum = LaplaceMechanism.execute(
            value=exact_sum, epsilon=epsilon, sensitivity=sensitivity
        )

        return private_sum / self.N
Ejemplo n.º 10
0
 def epsilon_for_confidence_interval(
     self, *, target_ci, delta, confidence=0.95
 ) -> float:
     return LaplaceMechanism.epsilon_for_confidence_interval(
         target_ci=target_ci, confidence=confidence, sensitivity=self.sensitivity,
     )
Ejemplo n.º 11
0
 def confidence_interval(self, *, epsilon, confidence=0.95) -> float:
     return LaplaceMechanism.confidence_interval(
         epsilon=epsilon, sensitivity=self.sensitivity, confidence=confidence,
     )
Ejemplo n.º 12
0
def test_laplace_mechanism_invocation():
    """Test a few variations of arguments for the Laplace Mechanism"""
    LaplaceMechanism.execute(value=0, epsilon=0.1, sensitivity=1)
    LaplaceMechanism.execute_batch(values=[], epsilon=0.1, sensitivity=1)
    LaplaceMechanism.execute_batch(values=[0, 1], epsilon=0.1, sensitivity=1)