# Copyright 2019 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """Tests Sobol sequence generator.""" import numpy as np from tensorflow.python.eager import def_function from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import tensor_spec from tensorflow.python.framework import test_util from tensorflow.python.ops import gen_math_ops from tensorflow.python.ops import math_ops from tensorflow.python.platform import googletest class SobolSampleOpTest(test_util.TensorFlowTestCase): def test_basic(self): for dtype in [np.float64, np.float32]: expected = np.array([[.5, .5], [.75, .25], [.25, .75], [.375, .375]]) sample = self.evaluate(math_ops.sobol_sample(2, 4, dtype=dtype)) self.assertAllClose(expected, sample, 0.001) def test_more_known_values(self): for dtype in [np.float64, np.float32]: sample = math_ops.sobol_sample(5, 31, dtype=dtype) expected = [[0.50, 0.50, 0.50, 0.50, 0.50], [0.75, 0.25, 0.25, 0.25, 0.75], [0.25, 0.75, 0.75, 0.75, 0.25], [0.375, 0.375, 0.625, 0.875, 0.375], [0.875, 0.875, 0.125, 0.375, 0.875], [0.625, 0.125, 0.875, 0.625, 0.625], [0.125, 0.625, 0.375, 0.125, 0.125], [0.1875, 0.3125, 0.9375, 0.4375, 0.5625], [0.6875, 0.8125, 0.4375, 0.9375, 0.0625], [0.9375, 0.0625, 0.6875, 0.1875, 0.3125], [0.4375, 0.5625, 0.1875, 0.6875, 0.8125], [0.3125, 0.1875, 0.3125, 0.5625, 0.9375], [0.8125, 0.6875, 0.8125, 0.0625, 0.4375], [0.5625, 0.4375, 0.0625, 0.8125, 0.1875], [0.0625, 0.9375, 0.5625, 0.3125, 0.6875], [0.09375, 0.46875, 0.46875, 0.65625, 0.28125], [0.59375, 0.96875, 0.96875, 0.15625, 0.78125], [0.84375, 0.21875, 0.21875, 0.90625, 0.53125], [0.34375, 0.71875, 0.71875, 0.40625, 0.03125], [0.46875, 0.09375, 0.84375, 0.28125, 0.15625], [0.96875, 0.59375, 0.34375, 0.78125, 0.65625], [0.71875, 0.34375, 0.59375, 0.03125, 0.90625], [0.21875, 0.84375, 0.09375, 0.53125, 0.40625], [0.15625, 0.15625, 0.53125, 0.84375, 0.84375], [0.65625, 0.65625, 0.03125, 0.34375, 0.34375], [0.90625, 0.40625, 0.78125, 0.59375, 0.09375], [0.40625, 0.90625, 0.28125, 0.09375, 0.59375], [0.28125, 0.28125, 0.15625, 0.21875, 0.71875], [0.78125, 0.78125, 0.65625, 0.71875, 0.21875], [0.53125, 0.03125, 0.40625, 0.46875, 0.46875], [0.03125, 0.53125, 0.90625, 0.96875, 0.96875]] self.assertAllClose(expected, self.evaluate(sample), .001) def test_skip(self): dim = 10 n = 50 skip = 17 for dtype in [np.float64, np.float32]: sample_noskip = math_ops.sobol_sample(dim, n + skip, dtype=dtype) sample_skip = math_ops.sobol_sample(dim, n, skip, dtype=dtype) self.assertAllClose( self.evaluate(sample_noskip)[skip:, :], self.evaluate(sample_skip)) def test_static_shape(self): s = math_ops.sobol_sample(10, 100, dtype=np.float32) self.assertAllEqual([100, 10], s.shape.as_list()) def test_static_shape_using_placeholder_for_dim(self): @def_function.function( input_signature=[tensor_spec.TensorSpec(shape=[], dtype=dtypes.int32)]) def f(dim): s = math_ops.sobol_sample(dim, 100, dtype=dtypes.float32) assert s.shape.as_list() == [100, None] return s self.assertAllEqual([100, 10], self.evaluate(f(10)).shape) def test_static_shape_using_placeholder_for_num_results(self): @def_function.function( input_signature=[tensor_spec.TensorSpec(shape=[], dtype=dtypes.int32)]) def f(num_results): s = math_ops.sobol_sample(10, num_results, dtype=dtypes.float32) assert s.shape.as_list() == [None, 10] return s self.assertAllEqual([100, 10], self.evaluate(f(100)).shape) def test_static_shape_using_only_placeholders(self): @def_function.function( input_signature=[tensor_spec.TensorSpec(shape=[], dtype=dtypes.int32)] * 2) def f(dim, num_results): s = math_ops.sobol_sample(dim, num_results, dtype=dtypes.float32) assert s.shape.as_list() == [None, None] return s self.assertAllEqual([100, 10], self.evaluate(f(10, 100)).shape) def test_dynamic_shape(self): s = math_ops.sobol_sample(10, 100, dtype=dtypes.float32) self.assertAllEqual([100, 10], self.evaluate(s).shape) def test_default_dtype(self): # Create an op without specifying the dtype. Dtype should be float32 in # this case. s = math_ops.sobol_sample(10, 100) self.assertEqual(dtypes.float32, s.dtype) @test_util.run_in_graph_and_eager_modes def test_non_scalar_input(self): with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError), r'Shape must be rank 0 but is rank 1|' r'\w+ must be a scalar'): self.evaluate(gen_math_ops.sobol_sample( dim=7, num_results=constant_op.constant([1, 0]), skip=constant_op.constant([1]))) @test_util.run_in_graph_and_eager_modes def test_dim_num_results_overflow(self): with self.assertRaisesRegex( (ValueError, errors.InvalidArgumentError), r'num_results\*dim must be less than 2147483647'): self.evaluate( gen_math_ops.sobol_sample( dim=2560, num_results=16384000, skip=0, dtype=dtypes.float32)) @test_util.run_in_graph_and_eager_modes def test_num_results_skip_overflow(self): with self.assertRaisesRegex( (ValueError, errors.InvalidArgumentError), r'num_results\+skip must be less than 2147483647', ): self.evaluate( gen_math_ops.sobol_sample( dim=1, num_results=1, skip=2147483647, dtype=dtypes.float32 ) ) if __name__ == '__main__': googletest.main()