def test_multinomial(self): # Test that raw_random.multinomial generates the same results as numpy. # Check over two calls to see if the random state is correctly updated. rng_R = random_state_type() post_r, out = multinomial(rng_R, (7, 3), 6, [0.2] * 5) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [out], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) (val0, ) = f() (val1, ) = f() numpy_val0 = numpy_rng.multinomial(6, [0.2] * 5, (7, 3)) numpy_val1 = numpy_rng.multinomial(6, [0.2] * 5, (7, 3)) assert np.all(val0 == numpy_val0) assert np.all(val1 == numpy_val1) assert val0.shape == (7, 3, 5) assert val1.shape == (7, 3, 5)
def test_poisson(self): # Test that raw_random.poisson generates the same results as numpy. # Check over two calls to see if the random state is correctly updated. rng_R = random_state_type() # Use non-default parameters, and larger dimensions because of # the integer nature of the result post_r, out = poisson(rng_R, lam=5, size=(11, 8)) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [out], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) val0 = f() val1 = f() numpy_val0 = numpy_rng.poisson(5, size=(11, 8)) numpy_val1 = numpy_rng.poisson(5, size=(11, 8)) assert np.allclose(val0, numpy_val0) assert np.allclose(val1, numpy_val1)
def test_binomial(self): # Test that raw_random.binomial generates the same results as numpy. # Check over two calls to see if the random state is correctly updated. rng_R = random_state_type() # Use non-default parameters, and larger dimensions because of # the integer nature of the result post_r, bin = binomial(rng_R, (7, 12), 5, 0.8) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [bin], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) val0 = f() val1 = f() numpy_val0 = numpy_rng.binomial(5, 0.8, size=(7, 12)) numpy_val1 = numpy_rng.binomial(5, 0.8, size=(7, 12)) assert np.all(val0 == numpy_val0) assert np.all(val1 == numpy_val1)
def test_normal(self): # Test that raw_random.normal generates the same results as numpy. # Check over two calls to see if the random state is correctly updated. rng_R = random_state_type() # Use non-default parameters post_r, out = normal(rng_R, (2, 3), 4.0, 2.0) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [out], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) val0 = f() val1 = f() numpy_val0 = numpy_rng.normal(4.0, 2.0, size=(2, 3)) numpy_val1 = numpy_rng.normal(4.0, 2.0, size=(2, 3)) assert np.allclose(val0, numpy_val0) assert np.allclose(val1, numpy_val1)
def test_random_function_ndim(self): # Test that random_function helper function accepts argument ndim rng_R = random_state_type() # ndim is an optional argument indicating the length of the 'shape' # ndim not specified, OK post_out4, out4 = uniform(rng_R, (4, )) # ndim specified, consistent with shape, OK post_out1_4, out1_4 = uniform(rng_R, (4, ), ndim=1) post_out2_4_4, out2_4_4 = uniform(rng_R, (4, 4), ndim=2) # ndim specified, but not compatible with shape with pytest.raises(ValueError): uniform(rng_R, (4, ), ndim=2) f_ok = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_out2_4_4, mutable=True, ) ], [out4, out1_4, out2_4_4], accept_inplace=True, ) # The correct cases should execute properly o4, o1_4, o2_4_4 = f_ok() # Check the sanity of the answers assert np.allclose(o4, o1_4) assert np.allclose(o4, o2_4_4[0])
def test_no_inplace(self): # Test that when not running inplace, the RandomState is not updated rf = RandomFunction("uniform", tensor.dvector) rng_R = random_state_type() post_r, out = rf(rng_R, (3, ), 0.0, 1.0) f = compile.function([rng_R], [post_r, out]) rng = np.random.RandomState(utt.fetch_seed()) rng0, val0 = f(rng) rng_ = np.random.RandomState(utt.fetch_seed()) # rng should still be in a fresh state assert rng_R.type.values_eq(rng, rng_) # rng0 should be in an updated state assert not rng_R.type.values_eq(rng, rng0) f2 = compile.function( [compile.In(rng_R, value=rng, update=post_r, mutable=False)], [post_r, out]) rng2, val2 = f2() # rng should be in a fresh state assert rng_R.type.values_eq(rng, rng_) # rng2 should be in an updated state assert not rng_R.type.values_eq(rng, rng2) # The updated state should be the same for both functions assert rng_R.type.values_eq(rng2, rng0) rng3, val3 = f2() # rng2 should not have changed assert rng_R.type.values_eq(rng2, rng0) # rng3 should be an updated again version of rng2 assert not rng_R.type.values_eq(rng3, rng2) assert not rng_R.type.values_eq(rng3, rng)
def test_inplace_optimization(self): # Test that FAST_RUN includes the random_make_inplace optimization # inplace = False rf2 = RandomFunction(np.random.RandomState.uniform, tensor.dvector) rng_R = random_state_type() # If calling RandomFunction directly, all args have to be specified, # because shape will have to be moved to the end post_r2, out2 = rf2(rng_R, (4, ), 0.0, 1.0) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r2, mutable=True, ) ], out2, mode="FAST_RUN", ) # DEBUG_MODE can't pass the id-based # test below # test that the RandomState object stays the same from function call to # function call, but that the values returned change from call to call. id0 = id(f[rng_R]) val0 = f() assert id0 == id(f[rng_R]) val1 = f() assert id0 == id(f[rng_R]) assert not np.allclose(val0, val1)
def test_random_function_noshape_args(self): # Test if random_function helper works with args but without shape rng_R = random_state_type() # No shape, default args -> OK post_out, out = uniform(rng_R, size=None, ndim=2) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_out, mutable=True, ) ], [out], accept_inplace=True, ) (o, ) = f() # No shape, args that have to be broadcasted -> OK low = tensor.TensorType(dtype="float64", broadcastable=(False, True, True))() high = tensor.TensorType(dtype="float64", broadcastable=(True, True, True, False))() post_out2, out2 = uniform(rng_R, size=None, ndim=2, low=low, high=high) assert out2.ndim == 4 assert out2.broadcastable == (True, False, True, False) g = compile.function( [ low, high, compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_out2, mutable=True, ), ], [out2], accept_inplace=True, ) low_v = [[[3]], [[4]], [[-5]]] high_v = [[[[5, 8]]]] (o2, ) = g(low_v, high_v) assert o2.shape == (1, 3, 1, 2)
def test_permutation(self): # Test that raw_random.permutation generates the same results as numpy. rng_R = random_state_type() post_r, out = permutation(rng_R, size=(9, ), n=6) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [out], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) # Check over two calls to see if the random state is correctly updated. # numpy_rng.permutation outputs one vector at a time, # so we call it iteratively to generate all the samples. val0 = f() val1 = f() numpy_val0 = np.asarray([numpy_rng.permutation(6) for i in range(9)]) numpy_val1 = np.asarray([numpy_rng.permutation(6) for i in range(9)]) assert np.all(val0 == numpy_val0) assert np.all(val1 == numpy_val1) # Test that we can generate a list: have size=None or (). for ndim in [1, None]: post_r, out = permutation(rng_R, n=10, size=None, ndim=ndim) inp = compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) f = aesara.function([inp], out) o = f() assert o.shape == (10, ) assert (np.sort(o) == np.arange(10)).all() # Wrong number of dimensions asked with pytest.raises(TypeError): permutation(rng_R, size=None, ndim=2)
def test_args(self): # Test that arguments to RandomFunction are honored rf2 = RandomFunction(np.random.RandomState.uniform, tensor.dvector) rf4 = RandomFunction(np.random.RandomState.uniform, tensor.dvector, inplace=True) rng_R = random_state_type() # use make_node to override some of the self.args post_r2, out2 = rf2(rng_R, (4, ), -2, 2) # NOT INPLACE post_r4, out4 = rf4(rng_R, (4, ), -4, 4) # INPLACE post_r2_4, out2_4 = rf2(rng_R, (4, ), -4.0, 2) # NOT INPLACE post_r2_4_4, out2_4_4 = rf2(rng_R, (4, ), -4.0, 4.0) # NOT INPLACE # configure out4 to be computed inplace # The update expression means that the random state rng_R will # be maintained by post_r4 f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r4, mutable=True, ) ], [out2, out4, out2_4, out2_4_4], accept_inplace=True, ) f2, f4, f2_4, f2_4_4 = f() f2b, f4b, f2_4b, f2_4_4b = f() # print f2 # print f4 # print f2_4 # print f2_4_4 # print f2b # print f4b # print f2_4b # print f2_4_4b # setting bounds is same as multiplying by 2 assert np.allclose(f2 * 2, f4), (f2, f4) # retrieving from non-inplace generator # is same as inplace one for first call assert np.allclose(f2_4_4, f4), (f2_4_4, f4) # f4 changes from call to call, that the update has worked assert not np.allclose(f4, f4b), (f4, f4b)
def test_permutation_helper(self): # Test that raw_random.permutation_helper generates the same # results as numpy, # and that the 'ndim_added' keyword behaves correctly. # permutation_helper needs "ndim_added=1", because its output # is one dimension more than its "shape" argument (and there's # no way to determine that automatically). # Check the working case, over two calls to see if the random # state is correctly updated. rf = RandomFunction(permutation_helper, tensor.imatrix, 8, ndim_added=1) rng_R = random_state_type() post_r, out = rf(rng_R, (7, ), 8) f = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r, mutable=True, ) ], [out], accept_inplace=True, ) numpy_rng = np.random.RandomState(utt.fetch_seed()) val0 = f() val1 = f() # numpy_rng.permutation outputs one vector at a time, # so we call it iteratively to generate all the samples. numpy_val0 = np.asarray([numpy_rng.permutation(8) for i in range(7)]) numpy_val1 = np.asarray([numpy_rng.permutation(8) for i in range(7)]) assert np.all(val0 == numpy_val0) assert np.all(val1 == numpy_val1) # This call lacks "ndim_added=1", so ndim_added defaults to 0. # A ValueError should be raised. rf0 = RandomFunction(permutation_helper, tensor.imatrix, 8) post_r0, out0 = rf0(rng_R, (7, ), 8) f0 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r0, mutable=True, ) ], [out0], accept_inplace=True, ) with pytest.raises(ValueError): f0() # Here, ndim_added is 2 instead of 1. A ValueError should be raised. rf2 = RandomFunction(permutation_helper, tensor.imatrix, 8, ndim_added=2) post_r2, out2 = rf2(rng_R, (7, ), 8) f2 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=post_r2, mutable=True, ) ], [out2], accept_inplace=True, ) with pytest.raises(ValueError): f2()
def test_random_function_ndim_added(self): # Test that random_function helper function accepts ndim_added as # keyword argument # If using numpy's uniform distribution, ndim_added should be 0, # because the shape provided as argument is the output shape. # Specifying a different ndim_added will change the Op's output ndim, # so np.uniform will produce a result of incorrect shape, # and a ValueError should be raised. def ndim_added_deco(ndim_added): def randomfunction(random_state, size=(), low=0.0, high=0.0, ndim=None): ndim, size, bcast = raw_random._infer_ndim_bcast(ndim, size) if ndim_added < 0: bcast = bcast[:ndim_added] else: bcast = bcast + ((False, ) * ndim_added) assert len(bcast) == ndim + ndim_added op = RandomFunction( "uniform", tensor.TensorType(dtype="float64", broadcastable=bcast), ndim_added=ndim_added, ) return op(random_state, size, low, high) return randomfunction uni_1 = ndim_added_deco(1) uni_0 = ndim_added_deco(0) uni_m1 = ndim_added_deco(-1) rng_R = random_state_type() p_uni11, uni11 = uni_1(rng_R, size=(4, )) p_uni12, uni12 = uni_1(rng_R, size=(3, 4)) p_uni01, uni01 = uni_0(rng_R, size=(4, )) p_uni02, uni02 = uni_0(rng_R, size=(3, 4)) p_unim11, unim11 = uni_m1(rng_R, size=(4, )) p_unim12, unim12 = uni_m1(rng_R, size=(3, 4)) assert uni11.ndim == 2 assert uni12.ndim == 3 assert uni01.ndim == 1 assert uni02.ndim == 2 assert unim11.ndim == 0 assert unim12.ndim == 1 f11 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=p_uni11, mutable=True, ) ], [uni11], accept_inplace=True, ) f12 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=p_uni12, mutable=True, ) ], [uni12], accept_inplace=True, ) fm11 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=p_unim11, mutable=True, ) ], [unim11], accept_inplace=True, ) fm12 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=p_unim12, mutable=True, ) ], [unim12], accept_inplace=True, ) f0 = compile.function( [ compile.In( rng_R, value=np.random.RandomState(utt.fetch_seed()), update=p_uni02, mutable=True, ) ], [uni01, uni02], accept_inplace=True, ) with pytest.raises(ValueError): f11() with pytest.raises(ValueError): f12() with pytest.raises(ValueError): fm11() with pytest.raises(ValueError): fm12() u01, u02 = f0() assert np.allclose(u01, u02[0])