# Path: diffprivlib/validation.py
# def check_bounds(bounds, shape=0, min_separation=0.0, dtype=float):
#     """Input validation for the ``bounds`` parameter.
# 
#     Checks that ``bounds`` is composed of a list of tuples of the form (lower, upper), where lower <= upper and both
#     are numeric.  Also checks that ``bounds`` contains the appropriate number of dimensions, and that there is a
#     ``min_separation`` between the bounds.
# 
#     Parameters
#     ----------
#     bounds : tuple
#         Tuple of bounds of the form (min, max). `min` and `max` can either be scalars or 1-dimensional arrays.
# 
#     shape : int, default: 0
#         Number of dimensions to be expected in ``bounds``.
# 
#     min_separation : float, default: 0.0
#         The minimum separation between `lower` and `upper` of each dimension.  This separation is enforced if not
#         already satisfied.
# 
#     dtype : data-type, default: float
#         Data type of the returned bounds.
# 
#     Returns
#     -------
#     bounds : tuple
# 
#     """
#     if not isinstance(bounds, tuple):
#         raise TypeError(f"Bounds must be specified as a tuple of (min, max), got {type(bounds)}.")
#     if not isinstance(shape, Integral):
#         raise TypeError(f"shape parameter must be integer-valued, got {type(shape)}.")
# 
#     lower, upper = bounds
# 
#     if np.asarray(lower).size == 1 or np.asarray(upper).size == 1:
#         lower = np.ravel(lower).astype(dtype)
#         upper = np.ravel(upper).astype(dtype)
#     else:
#         lower = np.asarray(lower, dtype=dtype)
#         upper = np.asarray(upper, dtype=dtype)
# 
#     if lower.shape != upper.shape:
#         raise ValueError("lower and upper bounds must be the same shape array")
#     if lower.ndim > 1:
#         raise ValueError("lower and upper bounds must be scalar or a 1-dimensional array")
#     if lower.size not in (1, shape):
#         raise ValueError(f"lower and upper bounds must have {shape or 1} element(s), got {lower.size}.")
# 
#     n_bounds = lower.shape[0]
# 
#     for i in range(n_bounds):
#         _lower = lower[i]
#         _upper = upper[i]
# 
#         if not isinstance(_lower, Real) or not isinstance(_upper, Real):
#             raise TypeError(f"Each bound must be numeric, got {_lower} ({type(_lower)}) and {_upper} ({type(_upper)}).")
# 
#         if _lower > _upper:
#             raise ValueError(f"For each bound, lower bound must be smaller than upper bound, got {lower}, {upper})")
# 
#         if _upper - _lower < min_separation:
#             mid = (_upper + _lower) / 2
#             lower[i] = mid - min_separation / 2
#             upper[i] = mid + min_separation / 2
# 
#     if shape == 0:
#         return lower.item(), upper.item()
# 
#     if n_bounds == 1:
#         lower = np.ones(shape, dtype=dtype) * lower.item()
#         upper = np.ones(shape, dtype=dtype) * upper.item()
# 
#     return lower, upper


from numbers import Real
from unittest import TestCase
from diffprivlib.validation import check_bounds
import numpy as np
    def test_incorrect_entries(self):
        with self.assertRaises(ValueError):
            check_bounds(([1, 2], 1))

        with self.assertRaises(ValueError):
            check_bounds(([1, 2], [1, 2, 3]))

        with self.assertRaises(ValueError):
            check_bounds(([1, 2], [1, 2], [1, 2]))

    def test_consistency(self):
        bounds = check_bounds(([1, 1], [2, 2]), shape=2)
        bounds2 = check_bounds(bounds, shape=2)
        self.assertTrue(np.all(bounds[0] == bounds2[0]))
        self.assertTrue(np.all(bounds[1] == bounds2[1]))

    def test_array_output(self):
        bounds = check_bounds(([1, 1], [2, 2]), shape=2)
        self.assertIsInstance(bounds[0], np.ndarray)
        self.assertIsInstance(bounds[1], np.ndarray)

    def test_scalar_output(self):
        bounds = check_bounds((1, 2), shape=0)
        self.assertIsInstance(bounds[0], Real)
        self.assertIsInstance(bounds[1], Real)

        bounds = check_bounds((1, 2), shape=0, dtype=int)
        self.assertIsInstance(bounds[0], int)
        self.assertIsInstance(bounds[1], int)


# Path: diffprivlib/validation.py
# def check_bounds(bounds, shape=0, min_separation=0.0, dtype=float):
#     """Input validation for the ``bounds`` parameter.
# 
#     Checks that ``bounds`` is composed of a list of tuples of the form (lower, upper), where lower <= upper and both
#     are numeric.  Also checks that ``bounds`` contains the appropriate number of dimensions, and that there is a
#     ``min_separation`` between the bounds.
# 
#     Parameters
#     ----------
#     bounds : tuple
#         Tuple of bounds of the form (min, max). `min` and `max` can either be scalars or 1-dimensional arrays.
# 
#     shape : int, default: 0
#         Number of dimensions to be expected in ``bounds``.
# 
#     min_separation : float, default: 0.0
#         The minimum separation between `lower` and `upper` of each dimension.  This separation is enforced if not
#         already satisfied.
# 
#     dtype : data-type, default: float
#         Data type of the returned bounds.
# 
#     Returns
#     -------
#     bounds : tuple
# 
#     """
#     if not isinstance(bounds, tuple):
#         raise TypeError(f"Bounds must be specified as a tuple of (min, max), got {type(bounds)}.")
#     if not isinstance(shape, Integral):
#         raise TypeError(f"shape parameter must be integer-valued, got {type(shape)}.")
# 
#     lower, upper = bounds
# 
#     if np.asarray(lower).size == 1 or np.asarray(upper).size == 1:
#         lower = np.ravel(lower).astype(dtype)
#         upper = np.ravel(upper).astype(dtype)
#     else:
#         lower = np.asarray(lower, dtype=dtype)
#         upper = np.asarray(upper, dtype=dtype)
# 
#     if lower.shape != upper.shape:
#         raise ValueError("lower and upper bounds must be the same shape array")
#     if lower.ndim > 1:
#         raise ValueError("lower and upper bounds must be scalar or a 1-dimensional array")
#     if lower.size not in (1, shape):
#         raise ValueError(f"lower and upper bounds must have {shape or 1} element(s), got {lower.size}.")
# 
#     n_bounds = lower.shape[0]
# 
#     for i in range(n_bounds):
#         _lower = lower[i]
#         _upper = upper[i]
# 
#         if not isinstance(_lower, Real) or not isinstance(_upper, Real):
#             raise TypeError(f"Each bound must be numeric, got {_lower} ({type(_lower)}) and {_upper} ({type(_upper)}).")
# 
#         if _lower > _upper:
#             raise ValueError(f"For each bound, lower bound must be smaller than upper bound, got {lower}, {upper})")
# 
#         if _upper - _lower < min_separation:
#             mid = (_upper + _lower) / 2
#             lower[i] = mid - min_separation / 2
#             upper[i] = mid + min_separation / 2
# 
#     if shape == 0:
#         return lower.item(), upper.item()
# 
#     if n_bounds == 1:
#         lower = np.ones(shape, dtype=dtype) * lower.item()
#         upper = np.ones(shape, dtype=dtype) * upper.item()
# 
#     return lower, upper


# Path: tests/test_check_bounds.py
from numbers import Real
from unittest import TestCase
from diffprivlib.validation import check_bounds
import numpy as np

    def test_incorrect_entries(self):
        with self.assertRaises(ValueError):
            check_bounds(([1, 2], 1))

        with self.assertRaises(ValueError):
            check_bounds(([1, 2], [1, 2, 3]))

        with self.assertRaises(ValueError):
            check_bounds(([1, 2], [1, 2], [1, 2]))

    def test_consistency(self):
        bounds = check_bounds(([1, 1], [2, 2]), shape=2)
        bounds2 = check_bounds(bounds, shape=2)
        self.assertTrue(np.all(bounds[0] == bounds2[0]))
        self.assertTrue(np.all(bounds[1] == bounds2[1]))

    def test_array_output(self):
        bounds = check_bounds(([1, 1], [2, 2]), shape=2)
        self.assertIsInstance(bounds[0], np.ndarray)
        self.assertIsInstance(bounds[1], np.ndarray)

    def test_scalar_output(self):
        bounds = check_bounds((1, 2), shape=0)
        self.assertIsInstance(bounds[0], Real)
        self.assertIsInstance(bounds[1], Real)

        bounds = check_bounds((1, 2), shape=0, dtype=int)
        self.assertIsInstance(bounds[0], int)
        self.assertIsInstance(bounds[1], int)


        bounds = check_bounds((1, 2), shape=0, dtype=float)