# Path: diffprivlib/mechanisms/laplace.py
# class Laplace(DPMechanism):
#     r"""
#     The classical Laplace mechanism in differential privacy.
# 
#     First proposed by Dwork, McSherry, Nissim and Smith [DMNS16]_, with support for (relaxed)
#     :math:`(\epsilon,\delta)`-differential privacy [HLM15]_.
# 
#     Samples from the Laplace distribution are generated using 4 uniform variates, as detailed in [HB21]_, to prevent
#     against reconstruction attacks due to limited floating point precision.
# 
#     Parameters
#     ----------
#     epsilon : float
#         Privacy parameter :math:`\epsilon` for the mechanism.  Must be in [0, ∞].
# 
#     delta : float, default: 0.0
#         Privacy parameter :math:`\delta` for the mechanism.  Must be in [0, 1].  Cannot be simultaneously zero with
#         ``epsilon``.
# 
#     sensitivity : float
#         The sensitivity of the mechanism.  Must be in [0, ∞).
# 
#     References
#     ----------
#     .. [DMNS16] Dwork, Cynthia, Frank McSherry, Kobbi Nissim, and Adam Smith. "Calibrating noise to sensitivity in
#         private data analysis." Journal of Privacy and Confidentiality 7, no. 3 (2016): 17-51.
# 
#     .. [HLM15] Holohan, Naoise, Douglas J. Leith, and Oliver Mason. "Differential privacy in metric spaces: Numerical,
#         categorical and functional data under the one roof." Information Sciences 305 (2015): 256-268.
# 
#     .. [HB21] Holohan, Naoise, and Stefano Braghin. "Secure Random Sampling in Differential Privacy." arXiv preprint
#         arXiv:2107.10138 (2021).
# 
#     """
#     def __init__(self, *, epsilon, delta=0.0, sensitivity):
#         super().__init__(epsilon=epsilon, delta=delta)
#         self.sensitivity = self._check_sensitivity(sensitivity)
#         self._scale = None
# 
#     @classmethod
#     def _check_sensitivity(cls, sensitivity):
#         if not isinstance(sensitivity, Real):
#             raise TypeError("Sensitivity must be numeric")
# 
#         if sensitivity < 0:
#             raise ValueError("Sensitivity must be non-negative")
# 
#         return float(sensitivity)
# 
#     def _check_all(self, value):
#         super()._check_all(value)
#         self._check_sensitivity(self.sensitivity)
# 
#         if not isinstance(value, Real):
#             raise TypeError("Value to be randomised must be a number")
# 
#         return True
# 
#     def bias(self, value):
#         """Returns the bias of the mechanism at a given `value`.
# 
#         Parameters
#         ----------
#         value : int or float
#             The value at which the bias of the mechanism is sought.
# 
#         Returns
#         -------
#         bias : float or None
#             The bias of the mechanism at `value`.
# 
#         """
#         return 0.0
# 
#     def variance(self, value):
#         """Returns the variance of the mechanism at a given `value`.
# 
#         Parameters
#         ----------
#         value : float
#             The value at which the variance of the mechanism is sought.
# 
#         Returns
#         -------
#         bias : float
#             The variance of the mechanism at `value`.
# 
#         """
#         self._check_all(0)
# 
#         return 2 * (self.sensitivity / (self.epsilon - np.log(1 - self.delta))) ** 2
# 
#     @staticmethod
#     def _laplace_sampler(unif1, unif2, unif3, unif4):
#         return np.log(1 - unif1) * np.cos(np.pi * unif2) + np.log(1 - unif3) * np.cos(np.pi * unif4)
# 
#     def randomise(self, value):
#         """Randomise `value` with the mechanism.
# 
#         Parameters
#         ----------
#         value : float
#             The value to be randomised.
# 
#         Returns
#         -------
#         float
#             The randomised value.
# 
#         """
#         self._check_all(value)
# 
#         scale = self.sensitivity / (self.epsilon - np.log(1 - self.delta))
#         standard_laplace = self._laplace_sampler(self._rng.random(), self._rng.random(), self._rng.random(),
#                                                  self._rng.random())
# 
#         return value - scale * standard_laplace
# 
# Path: diffprivlib/utils.py
# def copy_docstring(source):
#     """Decorator function to copy a docstring from a `source` function to a `target` function.
# 
#     The docstring is only copied if a docstring is present in `source`, and if none is present in `target`.  Takes
#     inspiration from similar in `matplotlib`.
# 
#     Parameters
#     ----------
#     source : method
#         Source function from which to copy the docstring.  If ``source.__doc__`` is empty, do nothing.
# 
#     Returns
#     -------
#     target : method
#         Target function with new docstring.
# 
#     """
#     def copy_func(target):
#         if source.__doc__ and not target.__doc__:
#             target.__doc__ = source.__doc__
#         return target
#     return copy_func


from numbers import Real
from diffprivlib.mechanisms.laplace import Laplace
from diffprivlib.utils import copy_docstring
import numpy as np

        if not isinstance(gamma, Real):
            raise TypeError("Gamma must be numeric")
        if not 0.0 <= gamma <= 1.0:
            raise ValueError("Gamma must be in [0,1]")

        return float(gamma)

    @copy_docstring(Laplace._check_all)
    def _check_all(self, value):
        super()._check_all(value)
        self._check_gamma(self.gamma)

        return True

    @classmethod
    def _check_epsilon_delta(cls, epsilon, delta):
        if not delta == 0:
            raise ValueError("Delta must be zero")

        return super()._check_epsilon_delta(epsilon, delta)

    @copy_docstring(Laplace.bias)
    def bias(self, value):
        return 0.0

    @copy_docstring(Laplace.variance)
    def variance(self, value):
        raise NotImplementedError


# Path: diffprivlib/mechanisms/laplace.py
# class Laplace(DPMechanism):
#     r"""
#     The classical Laplace mechanism in differential privacy.
# 
#     First proposed by Dwork, McSherry, Nissim and Smith [DMNS16]_, with support for (relaxed)
#     :math:`(\epsilon,\delta)`-differential privacy [HLM15]_.
# 
#     Samples from the Laplace distribution are generated using 4 uniform variates, as detailed in [HB21]_, to prevent
#     against reconstruction attacks due to limited floating point precision.
# 
#     Parameters
#     ----------
#     epsilon : float
#         Privacy parameter :math:`\epsilon` for the mechanism.  Must be in [0, ∞].
# 
#     delta : float, default: 0.0
#         Privacy parameter :math:`\delta` for the mechanism.  Must be in [0, 1].  Cannot be simultaneously zero with
#         ``epsilon``.
# 
#     sensitivity : float
#         The sensitivity of the mechanism.  Must be in [0, ∞).
# 
#     References
#     ----------
#     .. [DMNS16] Dwork, Cynthia, Frank McSherry, Kobbi Nissim, and Adam Smith. "Calibrating noise to sensitivity in
#         private data analysis." Journal of Privacy and Confidentiality 7, no. 3 (2016): 17-51.
# 
#     .. [HLM15] Holohan, Naoise, Douglas J. Leith, and Oliver Mason. "Differential privacy in metric spaces: Numerical,
#         categorical and functional data under the one roof." Information Sciences 305 (2015): 256-268.
# 
#     .. [HB21] Holohan, Naoise, and Stefano Braghin. "Secure Random Sampling in Differential Privacy." arXiv preprint
#         arXiv:2107.10138 (2021).
# 
#     """
#     def __init__(self, *, epsilon, delta=0.0, sensitivity):
#         super().__init__(epsilon=epsilon, delta=delta)
#         self.sensitivity = self._check_sensitivity(sensitivity)
#         self._scale = None
# 
#     @classmethod
#     def _check_sensitivity(cls, sensitivity):
#         if not isinstance(sensitivity, Real):
#             raise TypeError("Sensitivity must be numeric")
# 
#         if sensitivity < 0:
#             raise ValueError("Sensitivity must be non-negative")
# 
#         return float(sensitivity)
# 
#     def _check_all(self, value):
#         super()._check_all(value)
#         self._check_sensitivity(self.sensitivity)
# 
#         if not isinstance(value, Real):
#             raise TypeError("Value to be randomised must be a number")
# 
#         return True
# 
#     def bias(self, value):
#         """Returns the bias of the mechanism at a given `value`.
# 
#         Parameters
#         ----------
#         value : int or float
#             The value at which the bias of the mechanism is sought.
# 
#         Returns
#         -------
#         bias : float or None
#             The bias of the mechanism at `value`.
# 
#         """
#         return 0.0
# 
#     def variance(self, value):
#         """Returns the variance of the mechanism at a given `value`.
# 
#         Parameters
#         ----------
#         value : float
#             The value at which the variance of the mechanism is sought.
# 
#         Returns
#         -------
#         bias : float
#             The variance of the mechanism at `value`.
# 
#         """
#         self._check_all(0)
# 
#         return 2 * (self.sensitivity / (self.epsilon - np.log(1 - self.delta))) ** 2
# 
#     @staticmethod
#     def _laplace_sampler(unif1, unif2, unif3, unif4):
#         return np.log(1 - unif1) * np.cos(np.pi * unif2) + np.log(1 - unif3) * np.cos(np.pi * unif4)
# 
#     def randomise(self, value):
#         """Randomise `value` with the mechanism.
# 
#         Parameters
#         ----------
#         value : float
#             The value to be randomised.
# 
#         Returns
#         -------
#         float
#             The randomised value.
# 
#         """
#         self._check_all(value)
# 
#         scale = self.sensitivity / (self.epsilon - np.log(1 - self.delta))
#         standard_laplace = self._laplace_sampler(self._rng.random(), self._rng.random(), self._rng.random(),
#                                                  self._rng.random())
# 
#         return value - scale * standard_laplace
# 
# Path: diffprivlib/utils.py
# def copy_docstring(source):
#     """Decorator function to copy a docstring from a `source` function to a `target` function.
# 
#     The docstring is only copied if a docstring is present in `source`, and if none is present in `target`.  Takes
#     inspiration from similar in `matplotlib`.
# 
#     Parameters
#     ----------
#     source : method
#         Source function from which to copy the docstring.  If ``source.__doc__`` is empty, do nothing.
# 
#     Returns
#     -------
#     target : method
#         Target function with new docstring.
# 
#     """
#     def copy_func(target):
#         if source.__doc__ and not target.__doc__:
#             target.__doc__ = source.__doc__
#         return target
#     return copy_func


# Path: diffprivlib/mechanisms/staircase.py
from numbers import Real
from diffprivlib.mechanisms.laplace import Laplace
from diffprivlib.utils import copy_docstring
import numpy as np


        if not isinstance(gamma, Real):
            raise TypeError("Gamma must be numeric")
        if not 0.0 <= gamma <= 1.0:
            raise ValueError("Gamma must be in [0,1]")

        return float(gamma)

    @copy_docstring(Laplace._check_all)
    def _check_all(self, value):
        super()._check_all(value)
        self._check_gamma(self.gamma)

        return True

    @classmethod
    def _check_epsilon_delta(cls, epsilon, delta):
        if not delta == 0:
            raise ValueError("Delta must be zero")

        return super()._check_epsilon_delta(epsilon, delta)

    @copy_docstring(Laplace.bias)
    def bias(self, value):
        return 0.0

    @copy_docstring(Laplace.variance)
    def variance(self, value):
        raise NotImplementedError


    @copy_docstring(Laplace.randomise)