def main() -> None: if len(sys.argv) < 4: print("Usage: python main_minimal.py <seed> <config-file> " "<num-generations> <tsp-instance-file>") sys.exit(1) ######################################## # Read the command-line arguments and the instance ######################################## seed = int(sys.argv[1]) configuration_file = sys.argv[2] num_generations = int(sys.argv[3]) instance_file = sys.argv[4] print("Reading data...") instance = TSPInstance(instance_file) ######################################## # Read algorithm parameters ######################################## print("Reading parameters...") brkga_params, _ = load_configuration(configuration_file) ######################################## # Build the BRKGA data structures and initialize ######################################## print("Building BRKGA data and initializing...") decoder = TSPDecoder(instance) brkga = BrkgaMpIpr(decoder=decoder, sense=Sense.MINIMIZE, seed=seed, chromosome_size=instance.num_nodes, params=brkga_params) # NOTE: don't forget to initialize the algorithm. brkga.initialize() ######################################## # Find good solutions / evolve ######################################## print(f"Evolving {num_generations} generations...") brkga.evolve(num_generations) best_cost = brkga.get_best_fitness() print(f"Best cost: {best_cost}")
def test_evolve(self): """ Tests evolve() method. """ param_values = deepcopy(self.default_param_values) brkga_params = param_values["params"] brkga = BrkgaMpIpr(**param_values) # Not initialized with self.assertRaises(RuntimeError) as context: brkga.evolve() self.assertEqual( str(context.exception).strip(), "The algorithm hasn't been initialized. " "Call 'initialize()' before 'evolve()'") brkga.initialize() with self.assertRaises(ValueError) as context: brkga.evolve(-1) self.assertEqual( str(context.exception).strip(), "Number of generations must be large than one. " "Given -1") with open(os.path.join(STATE_DIR, "state5.pickle"), "rb") as hd: brkga = pickle.load(hd) with open(os.path.join(SOLUTION_DIR, "best_solution5.pickle"), "rb") as hd: results = pickle.load(hd) brkga.evolve() self.assertEqual(brkga.get_best_fitness(), results["fitness1"]) self.assertEqual(brkga.get_best_chromosome(), results["chromosome1"]) print(f"Elapsed time: {time() - self.start_time :.2f}") brkga.evolve(10) self.assertEqual(brkga.get_best_fitness(), results["fitness10"]) self.assertEqual(brkga.get_best_chromosome(), results["chromosome10"]) print(f"Elapsed time: {time() - self.start_time :.2f}") brkga.evolve(100) self.assertEqual(brkga.get_best_fitness(), results["fitness100"]) self.assertEqual(brkga.get_best_chromosome(), results["chromosome100"]) print(f"Elapsed time: {time() - self.start_time :.2f}")
def main() -> None: """ Proceeds with the optimization. Create to avoid spread `global` keywords around the code. """ args = docopt.docopt(__doc__) # print(args) configuration_file = args["--config_file"] instance_file = args["--instance_file"] seed = int(args["--seed"]) stop_rule = StopRule(args["--stop_rule"]) if stop_rule == StopRule.TARGET: stop_argument = float(args["--stop_arg"]) else: stop_argument = int(args["--stop_arg"]) maximum_time = float(args["--max_time"]) if maximum_time <= 0.0: raise RuntimeError(f"Maximum time must be larger than 0.0. " f"Given {maximum_time}.") perform_evolution = not args["--no_evolution"] ######################################## # Load config file and show basic info. ######################################## brkga_params, control_params = load_configuration(configuration_file) print(f"""------------------------------------------------------ > Experiment started at {datetime.now()} > Instance: {instance_file} > Configuration: {configuration_file} > Algorithm Parameters:""", end="") if not perform_evolution: print("> - Simple multi-start: on (no evolutionary operators)") else: output_string = "" for name, value in vars(brkga_params).items(): output_string += f"\n> -{name} {value}" for name, value in vars(control_params).items(): output_string += f"\n> -{name} {value}" print(output_string) print(f"""> Seed: {seed} > Stop rule: {stop_rule} > Stop argument: {stop_argument} > Maximum time (s): {maximum_time} ------------------------------------------------------""") ######################################## # Load instance and adjust BRKGA parameters ######################################## print(f"\n[{datetime.now()}] Reading TSP data...") instance = TSPInstance(instance_file) print(f"Number of nodes: {instance.num_nodes}") print(f"\n[{datetime.now()}] Generating initial tour...") # Generate a greedy solution to be used as warm start for BRKGA. initial_cost, initial_tour = greedy_tour(instance) print(f"Initial cost: {initial_cost}") ######################################## # Build the BRKGA data structures and initialize ######################################## print(f"\n[{datetime.now()}] Building BRKGA data...") # Usually, it is a good idea to set the population size # proportional to the instance size. brkga_params.population_size = min(brkga_params.population_size, 10 * instance.num_nodes) print(f"New population size: {brkga_params.population_size}") # Build a decoder object. decoder = TSPDecoder(instance) # Chromosome size is the number of nodes. # Each chromosome represents a permutation of nodes. brkga = BrkgaMpIpr(decoder=decoder, sense=Sense.MINIMIZE, seed=seed, chromosome_size=instance.num_nodes, params=brkga_params, evolutionary_mechanism_on=perform_evolution) # To inject the initial tour, we need to create chromosome representing # that solution. First, we create a set of keys to be used in the # chromosome. random.seed(seed) keys = sorted([random.random() for _ in range(instance.num_nodes)]) # Then, we visit each node in the tour and assign to it a key. initial_chromosome = [0] * instance.num_nodes for i in range(instance.num_nodes): initial_chromosome[initial_tour[i]] = keys[i] # Inject the warm start solution in the initial population. brkga.set_initial_population([initial_chromosome]) # NOTE: don't forget to initialize the algorithm. print(f"\n[{datetime.now()}] Initializing BRKGA data...") brkga.initialize() ######################################## # Warm up the script/code ######################################## # To make sure we are timing the runs correctly, we run some warmup # iterations with bogus data. Warmup is always recommended for script # languages. Here, we call the most used methods. print(f"\n[{datetime.now()}] Warming up...") bogus_alg = deepcopy(brkga) bogus_alg.evolve(2) # TODO (ceandrade): warm up path relink functions. # bogus_alg.path_relink(brkga_params.pr_type, brkga_params.pr_selection, # (x, y) -> 1.0, (x, y) -> true, 0, 0.5, 1, 10.0, 1.0) bogus_alg.get_best_fitness() bogus_alg.get_best_chromosome() bogus_alg = None ######################################## # Evolving ######################################## print(f"\n[{datetime.now()}] Evolving...") print("* Iteration | Cost | CurrentTime") best_cost = initial_cost * 2 best_chromosome = initial_chromosome iteration = 0 last_update_time = 0.0 last_update_iteration = 0 large_offset = 0 # TODO (ceandrade): enable the following when path relink is ready. # path_relink_time = 0.0 # num_path_relink_calls = 0 # num_homogenities = 0 # num_best_improvements = 0 # num_elite_improvements = 0 run = True # Main optimization loop. We evolve one generation at time, # keeping track of all changes during such process. start_time = time.time() while run: iteration += 1 # Evolves one iteration. brkga.evolve() # Checks the current results and holds the best. fitness = brkga.get_best_fitness() if fitness < best_cost: last_update_time = time.time() - start_time update_offset = iteration - last_update_iteration if large_offset < update_offset: large_offset = update_offset last_update_iteration = iteration best_cost = fitness best_chromosome = brkga.get_best_chromosome() print(f"* {iteration} | {best_cost:.0f} | {last_update_time:.2f}") # end if # TODO (ceandrade): implement path relink calls here. # Please, see Julia version for that. iter_without_improvement = iteration - last_update_iteration # Check stop criteria. run = not ( (time.time() - start_time > maximum_time) or (stop_rule == StopRule.GENERATIONS and iteration == stop_argument) or (stop_rule == StopRule.IMPROVEMENT and iter_without_improvement >= stop_argument) or (stop_rule == StopRule.TARGET and best_cost <= stop_argument)) # end while total_elapsed_time = time.time() - start_time total_num_iterations = iteration print(f"[{datetime.now()}] End of optimization\n") print(f"Total number of iterations: {total_num_iterations}") print(f"Last update iteration: {last_update_iteration}") print(f"Total optimization time: {total_elapsed_time:.2f}") print(f"Last update time: {last_update_time:.2f}") print(f"Large number of iterations between improvements: {large_offset}") # TODO (ceandrade): enable when path relink is ready. # print(f"\nTotal path relink time: {path_relink_time:.2f}") # print(f"\nTotal path relink calls: {num_path_relink_calls}") # print(f"\nNumber of homogenities: {num_homogenities}") # print(f"\nImprovements in the elite set: {num_elite_improvements}") # print(f"\nBest individual improvements: {num_best_improvements}") ######################################## # Extracting the best tour ######################################## tour = [] for (index, key) in enumerate(best_chromosome): tour.append((key, index)) tour.sort() print(f"\n% Best tour cost: {best_cost:.2f}") print("% Best tour: ", end="") for _, node in tour: print(node, end=" ") print( "\n\nInstance,Seed,NumNodes,TotalIterations,TotalTime," #"TotalPRTime,PRCalls,NumHomogenities,NumPRImprovElite," #"NumPrImprovBest," "LargeOffset,LastUpdateIteration,LastUpdateTime," "Cost") print( f"{basename(instance_file)}," f"{seed},{instance.num_nodes},{total_num_iterations}," f"{total_elapsed_time:.2f}," # f"{path_relink_time:.2f},{num_path_relink_calls}," # f"{num_homogenities},{num_elite_improvements},{num_best_improvements}," f"{large_offset},{last_update_iteration}," f"{last_update_time:.2f},{best_cost:.0f}")
def gen_conf5(): param_values = deepcopy(default_param_values) brkga_params = param_values["params"] chromosome_size = 100 instance = Instance(chromosome_size) brkga_params.population_size = 100 brkga_params.elite_percentage = 0.30 brkga_params.mutants_percentage = 0.20 brkga_params.num_elite_parents = 2 brkga_params.total_parents = 3 brkga_params.bias_type = BiasFunctionType.LOGINVERSE brkga_params.num_independent_populations = 3 brkga_params.pr_number_pairs = 0 brkga_params.pr_minimum_distance = 0.0 brkga_params.pr_type = PathRelinkingType.DIRECT brkga_params.pr_selection = PathRelinkingSelection.BESTSOLUTION brkga_params.alpha_block_size = 1.0 brkga_params.pr_percentage = 1.0 param_values["decoder"] = SumDecode(instance) param_values["sense"] = Sense.MINIMIZE param_values["seed"] = 4659930950303 param_values["chromosome_size"] = chromosome_size param_values["evolutionary_mechanism_on"] = True print("\n> Building configuration 5") brkga = BrkgaMpIpr(**param_values) brkga.initialize() print("> Writing configuration 5") with open(os.path.join(STATE_DIR, "state5.pickle"), "wb") as hd: pickle.dump(brkga, hd) print("> Evolving one generation...") brkga.evolve() fitness1 = brkga.get_best_fitness() chromosome1 = brkga.get_best_chromosome() print("> Evolving 10 generations...") brkga.evolve(10) fitness10 = brkga.get_best_fitness() chromosome10 = brkga.get_best_chromosome() print("> Evolving 100 generations...") brkga.evolve(100) fitness100 = brkga.get_best_fitness() chromosome100 = brkga.get_best_chromosome() with open(os.path.join(SOLUTION_DIR, "best_solution5.pickle"), "wb") as hd: pickle.dump( { "fitness1": fitness1, "chromosome1": chromosome1, "fitness10": fitness10, "chromosome10": chromosome10, "fitness100": fitness100, "chromosome100": chromosome100 }, hd ) print("fitness", fitness1) print("fitness", fitness10) print("fitness", fitness100)