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}")
Exemple #2
0
    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}")
Exemple #3
0
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)