Ejemplo n.º 1
0
def test_coin():
    # Always return true answer.
    mechanism = RandomizedResponse(values=["Yes", "No"],
                                   coin_p=1,
                                   default_value="<None>",
                                   mode=RandomizedResponseMode.coin)
    assert mechanism.anonymize("Yes") == "Yes"
    assert mechanism.anonymize("No") == "No"
    assert mechanism.anonymize("Foobar") == "<None>"

    # Throw error.
    mechanism = RandomizedResponse(values=["Yes", "No"],
                                   coin_p=1,
                                   mode=RandomizedResponseMode.coin)
    with pytest.raises(ValueError):
        mechanism.anonymize("Foobar")

    # Always return other answer.
    weights = DiscreteDistribution([[0, 1], [1, 0]])
    mechanism = RandomizedResponse(values=["Yes", "No"],
                                   coin_p=0,
                                   probability_distribution=weights,
                                   mode=RandomizedResponseMode.coin)
    assert mechanism.anonymize("Yes") == "No"
    assert mechanism.anonymize("No") == "Yes"
def test_matrix():
    random.seed(0)
    # Create distribution that always returns (input + 1) % n.
    weights = []
    for i in range(10):
        weights.append([0] * 10)
        weights[i][(i + 1) % 10] = 1
    d = DiscreteDistribution(weights)
    c = d.to_cumulative()
    for i in range(20):
        assert c.sample_element(i % 10, rng=random) == ((i + 1) % 10)

    # Check that multiplication on the diagonal by 1 always returns the input value (matrix case).
    d1 = d.with_rr_toss(1)
    c1 = d1.to_cumulative()
    assert [c1.sample_element(i, rng=random)
            for i in range(10)] == list(range(10))
def test_uniform():
    # Check that a uniform distribution is independent of its input.
    random.seed(0)
    d = DiscreteDistribution.uniform_distribution(10)
    assert len(d) == 10
    c = d.to_cumulative()
    elem1 = c.sample_element(0, rng=random)
    random.seed(0)
    elem2 = c.sample_element(1, rng=random)
    assert elem1 == elem2

    # Check that multiplication on the diagonal by 1 always returns the input value.
    d1 = d.with_rr_toss(1)
    c1 = d1.to_cumulative()
    assert [c1.sample_element(i, rng=random)
            for i in range(10)] == list(range(10))
Ejemplo n.º 4
0
    def __with_coin(cls, num_values, coin_p=0.5, probability_distribution=None):
        """
        Calculates the distribution for a mechanism that simulates the following experiment:
        1) Toss a coin (with heads having a probability `coin_p`, which defaults to 0.5).
        2) If heads, report true value.
        3) If tails, then throw another coin to randomly choose one element from `values`
           based on the `probability_distribution` (default is a uniform distribution).
           The probability distribution can be a list of weights.
           Alternatively, it can be a matrix where each row represents the list of weights for an input value,
           i.e., `probability_distribution[i][j]` is the probability of outputting value j given value i as an input.
        """
        if probability_distribution is None:
            d = DiscreteDistribution.uniform_distribution(num_values)
        else:
            d = probability_distribution

        d_rr = d.with_rr_toss(coin_p)
        return d_rr
Ejemplo n.º 5
0
    def __init__(self, **kwargs):
        """
        Initiates the randomized response mechanism.
        """
        super().__init__(**kwargs)

        # Build DiscreteDistribution object.
        distribution = (
            self.probability_distribution
            if self.probability_distribution is None or isinstance(self.probability_distribution, DiscreteDistribution)
            else DiscreteDistribution(self.probability_distribution)
        )

        # Create the cumulative probability distribution from the model.
        if self.mode == RandomizedResponseMode.dp:
            distribution = RandomizedResponse.__with_dp(len(self.values), self.epsilon)
        elif self.mode == RandomizedResponseMode.coin:
            distribution = RandomizedResponse.__with_coin(len(self.values), self.coin_p, distribution)

        # `distribution` cannot be None at this point if the model was validated.
        self.cum_distr = distribution.to_cumulative()
Ejemplo n.º 6
0
    def __with_dp(cls, t, epsilon):
        """
        Calculates the distribution for a DP mechanisms with `t` values and the privacy parameter `epsilon`.

        Let `t = len(values)`.
        This results in a probability of `e^epsilon / (t - 1 + e^epsilon)` for revealing the true value,
        and a probability of `1 / (t - 1 + e^epsilon)` for each other value.
        """
        e_eps = math.exp(epsilon)
        denominator = t - 1 + e_eps
        p_ii = e_eps / denominator
        p_ij = 1 / denominator

        # Create a matrix filled with p_ij
        weights = np.full((t, t), p_ij)
        # Create a matrix with diagonal entries p_ii - p_ij
        diag = np.zeros((t, t))
        np.fill_diagonal(diag, p_ii - p_ij)
        # Sum the two matrices to obtain our result
        weights += diag
        d = DiscreteDistribution(weights)
        return d
def test_others():
    with pytest.raises(ValueError):
        DiscreteDistribution(0)

    with pytest.raises(ValueError):
        DiscreteDistribution([[[1]]])

    with pytest.raises(ValueError):
        DiscreteDistribution(np.array([]))

    with pytest.raises(ValueError):
        DiscreteDistribution(np.array([[[1]]]))

    with pytest.raises(ValueError):
        DiscreteDistribution(np.array([1, [2, 3]]))

    with pytest.raises(ValueError):
        DiscreteDistribution(np.array([[1], [2, 3]]))
def test_simple():
    random.seed(0)
    with pytest.raises(ValueError):
        DiscreteDistribution([])

    # Create distribution that always returns 2.
    d = DiscreteDistribution([0, 0, 2, 0, 0])
    c = d.to_cumulative()
    for i in range(20):
        assert c.sample_element(i % 5, rng=random) == 2
    assert len(d) == 5
    assert len(c) == 5

    # Check that multiplication on the diagonal by 1 always returns the input value (simple case).
    weights = []
    for i in range(10):
        weights.append(random.randint(1, 10))
    d = DiscreteDistribution(weights)
    d1 = d.with_rr_toss(1)
    assert len(d1) == 10
    c1 = d1.to_cumulative()
    assert [c1.sample_element(i, rng=random)
            for i in range(10)] == list(range(10))
    assert len(c1) == 10