def three_d_grid_archive(): """Deterministic archive, but there are three behavior axes of different sizes, and some of the axes are not totally filled.""" archive = GridArchive([10, 10, 10], [(-2, 2), (-1, 1), (-2, 1)], seed=42) archive.initialize(solution_dim=3) add_uniform_3d_sphere(archive, (0, 2), (-1, 1), (-1, 0)) return archive
def _grid_archive(): """Deterministically created GridArchive.""" # The archive must be low-res enough that we can tell if the number of cells # is correct, yet high-res enough that we can see different colors. archive = GridArchive([10, 10], [(-1, 1), (-1, 1)], seed=42) archive.initialize(solution_dim=2) _add_uniform_sphere(archive, (-1, 1), (-1, 1)) return archive
def __init__(self): self.epsilon = 1e-10 self.n_forward_frames = 10 init_nn = NNGoL() set_nograd(init_nn) init_weights = get_init_weights(init_nn) env = GoLImitator(train_brute=TRAIN_BRUTE) if BC == 0: archive = GridArchive( [10, 10], [(-5, 5), (0, 5)], ) elif BC == 1: archive = GridArchive( [200], [(-10, 10)], ) elif BC == 2: archive = GridArchive( # [50, 50], [50, 50], [(0, 1), (0, 1)] # ) elif BC == 3: archive = GridArchive( [50, 50], # [(480, 490), (485, 486)]# [(0, 150)] * 2, ) emitters = [ ImprovementEmitter( # OptimizingEmitter( archive, init_weights, 0.05, batch_size=30, ) for _ in range(5) ] # env = gym.make("GoLImitator-v0") self.seed = 420 action_dim = env.action_space.shape obs_dim = env.observation_space.shape assert action_dim == obs_dim from ribs.optimizers import Optimizer optimizer = Optimizer(archive, emitters) self.optimizer = optimizer self.archive = archive self.init_nn = init_nn self.env = env
def test_dtypes(emitter_class, dtype): archive = GridArchive([20, 20], [(-1.0, 1.0)] * 2, dtype=dtype) archive.initialize(10) emitter = emitter_class(archive, np.zeros(10), 1.0) assert emitter.x0.dtype == dtype # Try running with the negative sphere function for a few iterations. for _ in range(10): sols = emitter.ask() objs = -np.sum(np.square(sols), axis=1) bcs = sols[:, :2] emitter.tell(sols, objs, bcs)
def test_tell_inserts_solutions_with_multiple_emitters(tell_metadata): archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) emitters = [ GaussianEmitter(archive, [0.0, 0.0], 1, batch_size=1), GaussianEmitter(archive, [0.5, 0.5], 1, batch_size=2), GaussianEmitter(archive, [-0.5, -0.5], 1, batch_size=3), ] optimizer = Optimizer(archive, emitters) _ = optimizer.ask() behavior_values = [[1.0, 1.0], [-1.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 0.0], [0.0, 1.0]] metadata = [f"metadata_{i}" for i in range(6)] if tell_metadata else None expected_metadata = metadata if tell_metadata else [None] * 6 # The sum of all the emitters' batch sizes is 6. optimizer.tell( objective_values=np.ones(6), behavior_values=behavior_values, metadata=metadata, ) # Note: This assumes data() returns entries in order of insertion, but this # may change in the future. all_sols, all_objs, all_behs, _, all_meta = optimizer.archive.data() assert len(all_sols) == 6 assert (behavior_values == all_behs).all() assert (all_objs == np.ones(6)).all() assert (expected_metadata == all_meta).all()
def test_list_as_initial_solution(emitter_class): archive = GridArchive([20, 20], [(-1.0, 1.0)] * 2) emitter = emitter_class(archive, [0.0] * 10, 1.0) # The list was passed in but should be converted to a numpy array. assert isinstance(emitter.x0, np.ndarray) assert (emitter.x0 == np.zeros(10)).all()
def test_from_config_with_valid_input(use_toml, tmp_path): seed = 42 batch_size = 4 archive = GridArchive([64, 64], [(-1, 1), (-1, 1)], seed=seed) emitters = [ GaussianEmitter(archive, [0.0, 0.0], 0.1, batch_size=batch_size, seed=seed) ] optimizer = Optimizer(archive, emitters) config_dict = { "archive": { "type": "GridArchive", "dims": [64, 64], "ranges": [(-1, 1), (-1, 1)], "seed": seed, }, "emitters": [{ "type": "GaussianEmitter", "x0": [0.0, 0.0], "sigma0": 0.1, "batch_size": batch_size, "seed": seed, }], "optimizer": { "type": "Optimizer", }, } if use_toml: config_path = tmp_path / "config.toml" with config_path.open("w") as file: toml.dump(config_dict, file) created_optimizer = ribs.factory.from_config(config_path) else: created_optimizer = ribs.factory.from_config(config_dict) # Check types. assert isinstance(created_optimizer, Optimizer) assert isinstance(created_optimizer.archive, GridArchive) assert len(created_optimizer.emitters) == 1 assert isinstance(created_optimizer.emitters[0], GaussianEmitter) # Check results from ask() and tell() -- since seeds are the same, all # results should be the same. optimizer_sols = optimizer.ask() created_optimizer_sols = created_optimizer.ask() assert len(optimizer_sols) == batch_size assert (optimizer_sols == created_optimizer_sols).all() objective_values = [0.0] * batch_size behavior_values = np.array([[1, 1], [-1, 1], [-1, -1], [1, -1]]) optimizer.tell(objective_values, behavior_values) created_optimizer.tell(objective_values, behavior_values) assert (optimizer.archive.as_pandas() == created_optimizer.archive.as_pandas()).all(None)
def optimizer_fixture(): """Returns an Optimizer with GridArchive and one GaussianEmitter.""" solution_dim = 2 num_solutions = 4 archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) emitters = [ GaussianEmitter(archive, [0.0, 0.0], 1, batch_size=num_solutions) ] return Optimizer(archive, emitters), solution_dim, num_solutions
def test_init_fails_on_non_unique_emitter_instances(): archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) # All emitters are the same instance. This is bad because the same emitter # gets called multiple times. emitters = [GaussianEmitter(archive, [0.0, 0.0], 1, batch_size=1)] * 5 with pytest.raises(ValueError): Optimizer(archive, emitters)
def test_init_fails_with_mismatched_emitters(): archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) emitters = [ # Emits 2D solutions. GaussianEmitter(archive, [0.0, 0.0], 1), # Mismatch -- emits 3D solutions rather than 2D solutions. GaussianEmitter(archive, [0.0, 0.0, 0.0], 1), ] with pytest.raises(ValueError): Optimizer(archive, emitters)
def setup(): archive = GridArchive((64, 64), [(-1, 1), (-1, 1)]) archive.initialize(solutions.shape[1]) # Let numba compile. archive.add(solutions[0], objective_values[0], behavior_values[0]) return (archive, ), {}
def test_heatmap_fails_on_non_2d(archive_type): archive = { "grid": lambda: GridArchive([20, 20, 20], [(-1, 1)] * 3), "cvt": lambda: CVTArchive(100, [(-1, 1)] * 3, samples=100), "sliding": lambda: SlidingBoundariesArchive([20, 20, 20], [(-1, 1)] * 3), }[archive_type]() archive.initialize(solution_dim=2) # Arbitrary. with pytest.raises(ValueError): { "grid": grid_archive_heatmap, "cvt": cvt_archive_heatmap, "sliding": sliding_boundaries_archive_heatmap, }[archive_type](archive)
def benchmark_get_10k_random_elites(benchmark, benchmark_data_10k): n, solutions, objective_values, behavior_values = benchmark_data_10k archive = GridArchive((64, 64), [(-1, 1), (-1, 1)]) archive.initialize(solutions.shape[1]) for i in range(n): archive.add(solutions[i], objective_values[i], behavior_values[i]) @benchmark def get_elites(): for i in range(n): sol, obj, beh = archive.get_random_elite()
def benchmark_as_pandas_2025_items(benchmark): dim = 45 archive = GridArchive((dim, dim), [(-1, 1), (-1, 1)]) archive.initialize(10) for x in np.linspace(-1, 1, dim): for y in np.linspace(-1, 1, dim): sol = np.random.random(10) sol[0] = x sol[1] = y archive.add(sol, 1.0, np.array([x, y])) # Archive should be full. assert len(archive.as_pandas()) == dim * dim benchmark(archive.as_pandas)
def test_tell_inserts_solutions_with_multiple_emitters(): archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) emitters = [ GaussianEmitter(archive, [0.0, 0.0], 1, batch_size=1), GaussianEmitter(archive, [0.5, 0.5], 1, batch_size=2), GaussianEmitter(archive, [-0.5, -0.5], 1, batch_size=3), ] optimizer = Optimizer(archive, emitters) _ = optimizer.ask() # The sum of all the emitters' batch sizes is 6. optimizer.tell( objective_values=[1.0] * 6, behavior_values=[[1.0, 1.0], [-1.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 0.0], [0.0, 1.0]], ) assert len(optimizer.archive.as_pandas()) == 6
def create_optimizer(seed, n_emitters, sigma0, batch_size): """Creates the Optimizer based on given configurations. See lunar_lander_main() for description of args. Returns: A pyribs optimizer set up for CMA-ME (i.e. it has ImprovementEmitter's and a GridArchive). """ env = gym.make("LunarLander-v2") action_dim = env.action_space.n obs_dim = env.observation_space.shape[0] archive = GridArchive( [50, 50], # 50 bins in each dimension. [(-1.0, 1.0), (-3.0, 0.0)], # (-1, 1) for x-pos and (-3, 0) for y-vel. seed=seed, ) # If we create the emitters with identical seeds, they will all output the # same initial solutions. The algorithm should still work -- eventually, the # emitters will produce different solutions because they get different # responses when inserting into the archive. However, using different seeds # avoids this problem altogether. seeds = ([None] * n_emitters if seed is None else [seed + i for i in range(n_emitters)]) initial_model = np.zeros((action_dim, obs_dim)) emitters = [ ImprovementEmitter( archive, initial_model.flatten(), sigma0=sigma0, batch_size=batch_size, seed=s, ) for s in seeds ] optimizer = Optimizer(archive, emitters) return optimizer
def test_init_fails_with_no_emitters(): archive = GridArchive([100, 100], [(-1, 1), (-1, 1)]) emitters = [] with pytest.raises(ValueError): Optimizer(archive, emitters)
def test_fails_on_dim_mismatch(): with pytest.raises(ValueError): GridArchive( dims=[10] * 2, # 2D space here. ranges=[(-1, 1)] * 3, # But 3D space here. )
def test_invalid_dtype(): with pytest.raises(ValueError): GridArchive([20, 20], [(-1, 1)] * 2, dtype=np.int32)
def test_auto_batch_size(emitter_class): archive = GridArchive([20, 20], [(-1.0, 1.0)] * 2) emitter = emitter_class(archive, np.zeros(10), 1.0) assert emitter.batch_size is not None assert isinstance(emitter.batch_size, int)
if not (os.path.exists('logs_cmaes/tb_logs/')): os.mkdir('logs_cmaes/tb_logs/') tb_logdir = "logs_cmaes/tb_logs/" + str(i) os.mkdir(tb_logdir) writer = SummaryWriter(tb_logdir) ############################################################################################## #pyribs implementation if not opt.pycma: # archive, emitter, and optimizer for cma-es n_features = 100 #number of input features for the noise vector generator batch_size = 10 n_bins = [bins0, bins1] archive = GridArchive(n_bins, [bc_ranges[opt.bcs[0]], bc_ranges[opt.bcs[1]] ]) # behavior 0, behavior 1 if opt.cma_me: emitters = [ ImprovementEmitter(archive, np.zeros(n_features), 1.0, batch_size=batch_size) for _ in range(1) ] else: emitters = [ OptimizingEmitter(archive, np.zeros(n_features), 1.0, batch_size=batch_size) for _ in range(1) ]
def _long_grid_archive(): """Same as above, but the behavior space is longer in one direction.""" archive = GridArchive([10, 10], [(-2, 2), (-1, 1)], seed=42) archive.initialize(solution_dim=2) _add_uniform_sphere(archive, (-2, 2), (-1, 1)) return archive
def test_add_requires_init(): archive = GridArchive([20, 20], [(-1, 1)] * 2) with pytest.raises(RuntimeError): archive.add(np.array([1, 2, 3]), 1.0, np.array([1.0, 1.0]))
def archive_fixture(): """Provides a simple archive and initial solution.""" archive = GridArchive([10, 10], [(-1, 1), (-1, 1)]) x0 = np.array([1, 2, 3, 4]) archive.initialize(len(x0)) return archive, x0
def test_solution_dim_requires_init(): archive = GridArchive([20, 20], [(-1, 1)] * 2) with pytest.raises(RuntimeError): _ = archive.solution_dim
def get_archive_data(name, dtype=np.float64): """Returns ArchiveFixtureData to use for testing each archive. The archives vary, but there will always be an empty 2D archive, as well as a 2D archive with a single solution added to it. This solution will have a value of [1, 2, 3], its objective value will be 1.0, and its behavior values will be [0.25, 0.25]. The name is the name of an archive to create. It should come from ARCHIVE_NAMES. """ # Characteristics of a single solution to insert into archive_with_entry. solution = np.array([1, 2, 3]) objective_value = 1.0 behavior_values = np.array([0.25, 0.25]) grid_indices = None centroid = None if name == "GridArchive": # Grid archive with 10 bins and range (-1, 1) in first dim, and 20 bins # and range (-2, 2) in second dim. bins = 10 * 20 archive = GridArchive([10, 20], [(-1, 1), (-2, 2)], dtype=dtype) archive.initialize(len(solution)) archive_with_entry = GridArchive([10, 20], [(-1, 1), (-2, 2)], dtype=dtype) archive_with_entry.initialize(len(solution)) grid_indices = (6, 11) elif name.startswith("CVTArchive-"): # CVT archive with bounds (-1,1) and (-1,1), and 4 centroids at (0.5, # 0.5), (-0.5, 0.5), (-0.5, -0.5), and (0.5, -0.5). The entry in # archive_with_entry should match with centroid (0.5, 0.5). bins = 4 kd_tree = name == "CVTArchive-kd_tree" samples = [[0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5], [0.5, -0.5]] centroid = [0.5, 0.5] archive = CVTArchive(4, [(-1, 1), (-1, 1)], samples=samples, use_kd_tree=kd_tree, dtype=dtype) archive.initialize(len(solution)) archive_with_entry = CVTArchive(4, [(-1, 1), (-1, 1)], samples=samples, use_kd_tree=kd_tree, dtype=dtype) archive_with_entry.initialize(len(solution)) elif name == "SlidingBoundariesArchive": # Sliding boundary archive with 10 bins and range (-1, 1) in first dim, # and 20 bins and range (-2, 2) in second dim. bins = 10 * 20 archive = SlidingBoundariesArchive([10, 20], [(-1, 1), (-2, 2)], remap_frequency=100, buffer_capacity=1000, dtype=dtype) archive.initialize(len(solution)) archive_with_entry = SlidingBoundariesArchive([10, 20], [(-1, 1), (-2, 2)], remap_frequency=100, buffer_capacity=1000, dtype=dtype) archive_with_entry.initialize(len(solution)) grid_indices = (6, 11) archive_with_entry.add(solution, objective_value, behavior_values) return ArchiveFixtureData( archive, archive_with_entry, solution, objective_value, behavior_values, grid_indices, centroid, bins, )
def create_optimizer(algorithm, dim, seed): """Creates an optimizer based on the algorithm name. Args: algorithm (str): Name of the algorithm passed into sphere_main. dim (int): Dimensionality of the sphere function. seed (int): Main seed or the various components. Returns: Optimizer: A ribs Optimizer for running the algorithm. """ max_bound = dim / 2 * 5.12 bounds = [(-max_bound, max_bound), (-max_bound, max_bound)] initial_sol = np.zeros(dim) batch_size = 37 num_emitters = 15 # Create archive. if algorithm in [ "map_elites", "line_map_elites", "cma_me_imp", "cma_me_imp_mu", "cma_me_rd", "cma_me_rd_mu", "cma_me_opt", "cma_me_mixed" ]: archive = GridArchive((500, 500), bounds, seed=seed) elif algorithm in ["cvt_map_elites", "line_cvt_map_elites"]: archive = CVTArchive(10_000, bounds, samples=100_000, use_kd_tree=True) else: raise ValueError(f"Algorithm `{algorithm}` is not recognized") # Create emitters. Each emitter needs a different seed, so that they do not # all do the same thing. emitter_seeds = [None] * num_emitters if seed is None else list( range(seed, seed + num_emitters)) if algorithm in ["map_elites", "cvt_map_elites"]: emitters = [ GaussianEmitter(archive, initial_sol, 0.5, batch_size=batch_size, seed=s) for s in emitter_seeds ] elif algorithm in ["line_map_elites", "line_cvt_map_elites"]: emitters = [ IsoLineEmitter(archive, initial_sol, iso_sigma=0.1, line_sigma=0.2, batch_size=batch_size, seed=s) for s in emitter_seeds ] elif algorithm in ["cma_me_imp", "cma_me_imp_mu"]: selection_rule = "filter" if algorithm == "cma_me_imp" else "mu" emitters = [ ImprovementEmitter(archive, initial_sol, 0.5, batch_size=batch_size, selection_rule=selection_rule, seed=s) for s in emitter_seeds ] elif algorithm in ["cma_me_rd", "cma_me_rd_mu"]: selection_rule = "filter" if algorithm == "cma_me_rd" else "mu" emitters = [ RandomDirectionEmitter(archive, initial_sol, 0.5, batch_size=batch_size, selection_rule=selection_rule, seed=s) for s in emitter_seeds ] elif algorithm == "cma_me_opt": emitters = [ OptimizingEmitter(archive, initial_sol, 0.5, batch_size=batch_size, seed=s) for s in emitter_seeds ] elif algorithm == "cma_me_mixed": emitters = [ RandomDirectionEmitter( archive, initial_sol, 0.5, batch_size=batch_size, seed=s) for s in emitter_seeds[:7] ] + [ ImprovementEmitter( archive, initial_sol, 0.5, batch_size=batch_size, seed=s) for s in emitter_seeds[7:] ] return Optimizer(archive, emitters)