diff --git a/randomgen/tests/_shims.pxd b/randomgen/tests/_shims.pxd index 0f7499231..2ad5a8142 100644 --- a/randomgen/tests/_shims.pxd +++ b/randomgen/tests/_shims.pxd @@ -1,7 +1,13 @@ from cpython.pycapsule cimport PyCapsule_GetPointer, PyCapsule_IsValid from numpy.random cimport bitgen_t -from randomgen.broadcasting cimport constraint_type, cont, cont_f, disc +from randomgen.broadcasting cimport ( + constraint_type, + cont, + cont_f, + disc, + float_fill_from_double, +) from randomgen.common cimport ( byteswap_little_endian, int_to_array, diff --git a/randomgen/tests/_shims.pyx b/randomgen/tests/_shims.pyx index 94abc4586..b566ab6ef 100644 --- a/randomgen/tests/_shims.pyx +++ b/randomgen/tests/_shims.pyx @@ -69,7 +69,7 @@ cdef class ShimGenerator: def cont_1_float(self, a, size=None, out=None): return cont_f(&float_1, &self._bitgen, size, self.lock, - a, "a", constraint_type.CONS_NONE, out) + a, "a", constraint_type.CONS_POSITIVE, out) def disc_0(self, size=None): return disc(&int_0, &self._bitgen, size, self.lock, @@ -81,34 +81,39 @@ cdef class ShimGenerator: def disc_d(self, a, size=None): return disc(&int_d, &self._bitgen, size, self.lock, 1, 0, - a, "a", constraint_type.CONS_NONE, + a, "a", constraint_type.CONS_POSITIVE, 0, "", constraint_type.CONS_NONE, 0, "", constraint_type.CONS_NONE) def disc_dd(self, a, b, size=None): return disc(&int_dd, &self._bitgen, size, self.lock, 2, 0, - a, "a", constraint_type.CONS_NONE, - b, "b", constraint_type.CONS_NONE, + a, "a", constraint_type.CONS_POSITIVE, + b, "b", constraint_type.CONS_NON_NEGATIVE, 0, "", constraint_type.CONS_NONE) def disc_di(self, a, b, size=None): return disc(&int_di, &self._bitgen, size, self.lock, 1, 1, - a, "a", constraint_type.CONS_NONE, - b, "b", constraint_type.CONS_NONE, + a, "a", constraint_type.CONS_POSITIVE, + b, "b", constraint_type.CONS_NON_NEGATIVE, 0, "", constraint_type.CONS_NONE) def disc_i(self, a, size=None): return disc(&int_i, &self._bitgen, size, self.lock, 0, 1, - a, "a", constraint_type.CONS_NONE, + a, "a", constraint_type.CONS_NON_NEGATIVE, 0, "", constraint_type.CONS_NONE, 0, "", constraint_type.CONS_NONE) def disc_iii(self, a, b, c, size=None): return disc(&int_iii, &self._bitgen, size, self.lock, 0, 3, - a, "a", constraint_type.CONS_NONE, - b, "b", constraint_type.CONS_NONE, - c, "c", constraint_type.CONS_NONE) + a, "a", constraint_type.CONS_POSITIVE, + b, "b", constraint_type.CONS_NON_NEGATIVE, + c, "c", constraint_type.CONS_POSITIVE) + + def cont_f_fill(self, size=None, out=None): + return float_fill_from_double( + &double0_func, &self._bitgen, size, self.lock, out + ) diff --git a/randomgen/tests/test_broadcasting.py b/randomgen/tests/test_broadcasting.py index 6e725c12f..865781237 100644 --- a/randomgen/tests/test_broadcasting.py +++ b/randomgen/tests/test_broadcasting.py @@ -212,3 +212,141 @@ def test_disc_iii(config): assert res == 25 else: assert_array_equal(res, np.full_like(res, 25)) + + +def test_constraint_violations(): + generator = ShimGenerator(PCG64()) + with pytest.raises(ValueError): + generator.cont_1(-1.0) + with pytest.raises(ValueError): + generator.cont_1([-1.0]) + with pytest.raises(ValueError): + generator.cont_1(np.array([1.0, -1.0])) + with pytest.raises(ValueError): + generator.cont_2(0, 1) + with pytest.raises(ValueError): + generator.cont_2(np.array([0.0]), 1) + with pytest.raises(ValueError): + generator.cont_2(1, np.nan) + with pytest.raises(ValueError): + generator.cont_2(np.array([1.0]), np.array([2.0, np.nan])) + with pytest.raises(ValueError): + generator.cont_2([1.0], [2.0, np.nan]) + with pytest.raises(ValueError): + generator.cont_3(2.0, 0.5, 1.5) + with pytest.raises(ValueError): + generator.cont_3(0.5, 0.0, 1.5) + with pytest.raises(ValueError): + generator.cont_3(0.5, 0.5, 0.5) + with pytest.raises(ValueError): + generator.cont_3(np.array([0.5, 2.0]), [0.5], np.array([1.5])) + with pytest.raises(ValueError): + generator.cont_3([0.5], [0.5, 0.0], [1.5]) + with pytest.raises(ValueError): + generator.cont_3([0.5], [0.5], np.array([1.5, 0.5])) + + with pytest.raises(ValueError): + generator.cont_3_alt_cons(0.5, 1, 1) + poisson_lam_max = np.iinfo("int64").max - np.sqrt(np.iinfo("int64").max) * 10 + legacy_poisson_lam_max = np.iinfo("l").max - np.sqrt(np.iinfo("l").max) * 10 + with pytest.raises(ValueError): + generator.cont_3_alt_cons(1.5, poisson_lam_max + 10000, 1) + with pytest.raises(ValueError): + generator.cont_3_alt_cons(1.5, 1, legacy_poisson_lam_max + 10000) + with pytest.raises(ValueError): + generator.cont_3_alt_cons([1.5, 0.5], [1], [1]) + with pytest.raises(ValueError): + generator.cont_3_alt_cons([1.5], [1, poisson_lam_max + 10000], [1]) + with pytest.raises(ValueError): + generator.cont_3_alt_cons([1.5], [1], [1, legacy_poisson_lam_max + 10000]) + + with pytest.raises(ValueError): + generator.cont_1_float(-2.0) + with pytest.raises(ValueError): + generator.cont_1_float([-2.0]) + with pytest.raises(ValueError): + generator.cont_1_float([3, 4, 5, -2.0]) + with pytest.raises(ValueError): + generator.disc_d(-1.0) + with pytest.raises(ValueError): + generator.disc_d([-1.0]) + with pytest.raises(ValueError): + generator.disc_d([100, -1.0]) + + with pytest.raises(ValueError): + generator.disc_dd(0.0, 4) + with pytest.raises(ValueError): + generator.disc_dd(1.0, -1) + with pytest.raises(ValueError): + generator.disc_dd([1.0, 0.0], [0.0, 0.0]) + with pytest.raises(ValueError): + generator.disc_dd([1.0, 1.0], [0.0, -0.1]) + + with pytest.raises(ValueError): + generator.disc_di(0.0, 0) + with pytest.raises(ValueError): + generator.disc_di(1.0, -1) + with pytest.raises(ValueError): + generator.disc_di([3, 0.0], 0) + with pytest.raises(ValueError): + generator.disc_di([4.5, 3.2], [3, -1]) + + with pytest.raises(ValueError): + generator.disc_i(-1) + generator.disc_i(0) + with pytest.raises(ValueError): + generator.disc_i([0, -1]) + + with pytest.raises(ValueError): + generator.disc_iii(0, 1, 1) + with pytest.raises(ValueError): + generator.disc_iii(1, -1, 1) + with pytest.raises(ValueError): + generator.disc_iii(1, 0, 0) + + with pytest.raises(ValueError): + generator.disc_iii([0], [1], [1]) + with pytest.raises(ValueError): + generator.disc_iii([1], [-1], [1]) + with pytest.raises(ValueError): + generator.disc_iii([1], [0], [0]) + + +def test_bad_output(): + with pytest.raises(ValueError): + generator.cont_1(0.5, size=(10, 10), out=np.empty((11, 11))) + with pytest.raises(ValueError): + generator.cont_2([[0.5, 1.5]], [[3.0], [4.0]], size=(3, 3)) + + +def test_bad_output_params(): + out = np.zeros((2, 2), order="F") + with pytest.raises(ValueError): + generator.cont_2([[0.5, 1.5]], [[3.0], [4.0]], out=out) + + out = np.zeros((4, 4)) + out = out[::2, ::2] + with pytest.raises(ValueError): + generator.cont_2([[0.5, 1.5]], [[3.0], [4.0]], out=out) + + out = np.zeros((2, 2), dtype=np.uint64) + with pytest.raises(TypeError): + generator.cont_2([[0.5, 1.5]], [[3.0], [4.0]], out=out) + + out = np.zeros(10) + with pytest.raises(ValueError): + generator.cont_2(0.5, [3.0], size=11, out=out) + + +def test_float_fill(): + res = generator.cont_f_fill() + assert_allclose(res, 3.141592) + res = generator.cont_f_fill((10, 11)) + assert_allclose(res, np.full_like(res, 3.141592)) + out = np.empty((3, 5), dtype=np.float32) + assert_allclose(res, np.full_like(res, 3.141592)) + res = generator.cont_f_fill(out=out) + assert_allclose(res, np.full_like(res, 3.141592)) + res = generator.cont_f_fill(size=out.shape, out=out) + assert_allclose(res, np.full_like(res, 3.141592)) + assert res is out