def testSobolGeneratorDedupe(self): generator = SobolGenerator(seed=0, deduplicate=True) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points, weights = generator.gen( n=2, bounds=bounds, linear_constraints=( np.array([[1, 1, 0, 0], [0, 1, 1, 0]]), np.array([1, 1]), ), fixed_features={fixed_param_index: 1}, rounding_func=lambda x: x, ) self.assertEqual(len(generated_points), 2) generated_points, weights = generator.gen( n=1, bounds=bounds, linear_constraints=( np.array([[1, 1, 0, 0], [0, 1, 1, 0]]), np.array([1, 1]), ), fixed_features={fixed_param_index: 1}, rounding_func=lambda x: x, ) self.assertEqual(len(generated_points), 1) self.assertIsNotNone(generator._get_state().get("generated_points"))
def testSobolGeneratorWithOrderConstraints(self): # Enforce dim_0 <= dim_1 <= dim_2 <= dim_3. # Enforce both fixed and tunable constraints. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=( np.array([[1, -1, 0, 0], [0, 1, -1, 0], [0, 0, 1, -1]]), np.array([0, 0, 0]), ), fixed_features={fixed_param_index: 0.5}, ) expected_points = np.array( [ [0.0625397, 0.18969421, 0.38985136, 0.5], [0.14849217, 0.26198292, 0.47683588, 0.5], [0.04088604, 0.08176377, 0.49635732, 0.5], ] ) self.assertTrue(np.shape(expected_points) == np.shape(generated_points)) self.assertTrue(np.allclose(expected_points, generated_points))
def _generate_sobol_points( n_sobol: int, bounds: List[Tuple[float, float]], device: torch.device, linear_constraints: Optional[Tuple[Tensor, Tensor]] = None, fixed_features: Optional[Dict[int, float]] = None, rounding_func: Optional[Callable[[Tensor], Tensor]] = None, model_gen_options: Optional[TConfig] = None, ) -> Tensor: linear_constraints_array = None if linear_constraints is not None: linear_constraints_array = ( linear_constraints[0].detach().numpy(), linear_constraints[1].detach().numpy(), ) array_rounding_func = None if rounding_func is not None: array_rounding_func = tensor_callable_to_array_callable( tensor_func=rounding_func, device=device) sobol = SobolGenerator(deduplicate=False, seed=np.random.randint(10000)) array_X, _ = sobol.gen( n=n_sobol, bounds=bounds, linear_constraints=linear_constraints_array, fixed_features=fixed_features, rounding_func=array_rounding_func, model_gen_options=model_gen_options, ) return torch.from_numpy(array_X).to(device)
def testSobolGeneratorNoScramble(self): generator = SobolGenerator(scramble=False) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points, weights = generator.gen( n=3, bounds=bounds, fixed_features={fixed_param_index: 1}) self.assertEqual(np.shape(generated_points), (3, 4)) np_bounds = np.array(bounds) self.assertTrue(np.alltrue(generated_points >= np_bounds[:, 0])) self.assertTrue(np.alltrue(generated_points <= np_bounds[:, 1]))
def testSobolGeneratorAllTunable(self): generator = SobolGenerator(seed=0) bounds = self._create_bounds(n_tunable=3, n_fixed=0) generated_points, weights = generator.gen(n=3, bounds=bounds) self.assertEqual(np.shape(generated_points), (3, 3)) np_bounds = np.array(bounds) self.assertTrue(np.alltrue(generated_points >= np_bounds[:, 0])) self.assertTrue(np.alltrue(generated_points <= np_bounds[:, 1])) self.assertTrue(np.all(weights == 1.0)) self.assertEqual(generator._get_state(), {"init_position": 3})
def testSobolGeneratorFixedSpace(self): generator = SobolGenerator(seed=0) bounds = self._create_bounds(n_tunable=0, n_fixed=2) n = 3 generated_points, _ = generator.gen( n=3, bounds=bounds, fixed_features={0: 1, 1: 2} ) expected_points = np.tile(np.array([[1, 2]]), (n, 1)) self.assertTrue(np.shape(expected_points) == np.shape(generated_points)) self.assertTrue(np.allclose(expected_points, generated_points))
def testSobolGeneratorOnlineRestart(self): # Ensure a single batch generation can also equivalently done by # a partial generation, re-initialization of a new SobolGenerator, # and a final generation. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points_single_batch, _ = generator.gen( n=3, bounds=bounds, fixed_features={fixed_param_index: 1}) generator_first_batch = SobolGenerator(seed=0) generated_points_first_batch, _ = generator_first_batch.gen( n=1, bounds=bounds, fixed_features={fixed_param_index: 1}) generator_second_batch = SobolGenerator( init_position=generator_first_batch.init_position, seed=0) generated_points_second_batch, _ = generator_second_batch.gen( n=2, bounds=bounds, fixed_features={fixed_param_index: 1}) generated_points_two_trials = np.vstack( (generated_points_first_batch, generated_points_second_batch)) self.assertTrue( np.shape(generated_points_single_batch) == np.shape( generated_points_two_trials)) self.assertTrue( np.allclose(generated_points_single_batch, generated_points_two_trials))
def testSobolGeneratorNoScramble(self): generator = SobolGenerator(scramble=False) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points, weights = generator.gen( n=3, bounds=bounds, fixed_features={fixed_param_index: 1}) expected_points = np.array([[0.5, 0.5, 0.5, 1.0], [0.75, 0.25, 0.75, 1.0], [0.25, 0.75, 0.25, 1.0]]) self.assertTrue( np.shape(expected_points) == np.shape(generated_points)) self.assertTrue(np.allclose(generated_points, expected_points))
def testSobolGeneratorFixedSpace(self): generator = SobolGenerator(seed=0) bounds = self._create_bounds(n_tunable=0, n_fixed=2) generated_points, _ = generator.gen(n=3, bounds=bounds, fixed_features={ 0: 1, 1: 2 }) self.assertEqual(np.shape(generated_points), (3, 2)) np_bounds = np.array(bounds) self.assertTrue(np.alltrue(generated_points >= np_bounds[:, 0])) self.assertTrue(np.alltrue(generated_points <= np_bounds[:, 1]))
def testSobolGeneratorMaxDraws(self): generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) with self.assertRaises(ValueError): generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=( np.array([[1, 1, 0, 0], [0, 1, 1, 0]]), np.array([1, 1]), ), fixed_features={fixed_param_index: 1}, model_gen_options={"max_rs_draws": 0}, )
def testSobolGeneratorAllTunable(self): generator = SobolGenerator(seed=0) bounds = self._create_bounds(n_tunable=3, n_fixed=0) generated_points, weights = generator.gen(n=3, bounds=bounds) expected_points = np.array([ [0.63552922, 0.17165081, 0.85513169], [0.92333341, 0.75570321, 0.72268772], [0.21601909, 0.48894, 0.11520141], ]) self.assertTrue( np.shape(expected_points) == np.shape(generated_points)) self.assertTrue(np.allclose(expected_points, generated_points)) self.assertTrue(np.all(weights == 1.0)) self.assertEqual(generator._get_state(), {"init_position": 3})
def get_sobol( search_space: SearchSpace, seed: Optional[int] = None, deduplicate: bool = False, init_position: int = 0, scramble: bool = True, ) -> RandomModelBridge: """Instantiates a Sobol sequence quasi-random generator. Args: search_space: Sobol generator search space. kwargs: Custom args for sobol generator. Returns: RandomModelBridge, with SobolGenerator as model. """ return RandomModelBridge( search_space=search_space, model=SobolGenerator( seed=seed, deduplicate=deduplicate, init_position=init_position, scramble=scramble, ), transforms=Cont_X_trans, )
def testSobolGeneratorFallbackToPolytopeSampler(self): # Ten parameters with sum less than 1. In this example, the rejection # sampler gives a search space exhausted error. Testing fallback to # polytope sampler when encountering this error. generator = SobolGenerator(seed=0, fallback_to_sample_polytope=True) bounds = self._create_bounds(n_tunable=10, n_fixed=0) A = np.ones((1, 10)) b = np.array([1]).reshape((1, 1)) generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=( A, b, ), ) self.assertTrue(np.shape(generated_points) == (3, 10)) self.assertTrue(np.alltrue(generated_points @ A.transpose() <= b))
def test_deduplicate(self): sobol = RandomModelBridge( search_space=get_small_discrete_search_space(), model=SobolGenerator(deduplicate=True), transforms=Cont_X_trans, ) for _ in range(4): # Search space is {[0, 1], {"red", "panda"}} self.assertEqual(len(sobol.gen(1).arms), 1) with self.assertRaises(SearchSpaceExhausted): sobol.gen(1)
def testSobolGeneratorOnline(self): # Verify that the generator will return the expected arms if called # one at a time. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) n = 3 expected_points = np.array([ [0.63552922, 0.17165081, 0.85513169, 1], [0.92333341, 0.75570321, 0.72268772, 1], [0.21601909, 0.48894, 0.11520141, 1], ]) for i in range(n): generated_points, weights = generator.gen( n=1, bounds=bounds, fixed_features={fixed_param_index: 1}) self.assertEqual(weights, [1]) self.assertTrue( np.allclose(generated_points, expected_points[i, :]))
def testSobolGeneratorWithOrderConstraints(self): # Enforce dim_0 <= dim_1 <= dim_2 <= dim_3. # Enforce both fixed and tunable constraints. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) A = np.array([[1, -1, 0, 0], [0, 1, -1, 0], [0, 0, 1, -1]]) b = np.array([0, 0, 0]) generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=(A, b), fixed_features={fixed_param_index: 0.5}, ) self.assertEqual(np.shape(generated_points), (3, 4)) self.assertTrue(np.alltrue(generated_points[..., -1] == 0.5)) self.assertTrue( np.array_equal( np.sort(generated_points[..., :-1], axis=-1), generated_points[..., :-1], ))
def testSobolGeneratorWithLinearConstraints(self): # Enforce dim_0 <= dim_1 <= dim_2 <= dim_3. # Enforce both fixed and tunable constraints. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) A = np.array([[1, 1, 0, 0], [0, 1, 1, 0]]) b = np.array([1, 1]) generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=( A, b, ), fixed_features={fixed_param_index: 1}, ) self.assertTrue(np.shape(generated_points) == (3, 4)) self.assertTrue(np.alltrue(generated_points[..., -1] == 1)) self.assertTrue(np.alltrue(generated_points @ A.transpose() <= b))
def testSobolGeneratorWithLinearConstraints(self): # Enforce dim_0 <= dim_1 <= dim_2 <= dim_3. # Enforce both fixed and tunable constraints. generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) generated_points, weights = generator.gen( n=3, bounds=bounds, linear_constraints=( np.array([[1, 1, 0, 0], [0, 1, 1, 0]]), np.array([1, 1]), ), fixed_features={fixed_param_index: 1}, ) expected_points = np.array([ [0.21601909, 0.48894, 0.11520141, 1.0], [0.28908476, 0.00287463, 0.54073817, 1.0], [0.0625397, 0.18969421, 0.38985136, 1.0], ]) self.assertTrue( np.shape(expected_points) == np.shape(generated_points)) self.assertTrue(np.allclose(expected_points, generated_points))
def testSobolGeneratorOnline(self): # Verify that the generator will return the expected arms if called # one at a time. bulk_generator = SobolGenerator(seed=0) generator = SobolGenerator(seed=0) n_tunable = fixed_param_index = 3 bounds = self._create_bounds(n_tunable=n_tunable, n_fixed=1) bulk_generated_points, bulk_weights = bulk_generator.gen( n=3, bounds=bounds, fixed_features={fixed_param_index: 1}) np_bounds = np.array(bounds) for expected_points in bulk_generated_points: generated_points, weights = generator.gen( n=1, bounds=bounds, fixed_features={fixed_param_index: 1}) self.assertEqual(weights, [1]) self.assertTrue(np.alltrue(generated_points >= np_bounds[:, 0])) self.assertTrue(np.alltrue(generated_points <= np_bounds[:, 1])) self.assertTrue(generated_points[..., -1] == 1) self.assertTrue( np.array_equal(expected_points, generated_points.flatten()))
def get_sobol(search_space: SearchSpace) -> RandomModelBridge: return RandomModelBridge( search_space=search_space, model=SobolGenerator(), transforms=Cont_X_trans, )
def testSobolGeneratorBadBounds(self): generator = SobolGenerator() with self.assertRaises(ValueError): generated_points, weights = generator.gen(n=1, bounds=[(-1, 1)])