Exemplo n.º 1
0
    def test_initialize(self):
        """
        Tests initialize() method.
        """

        # Double initialization.
        param_values = deepcopy(self.default_param_values)
        brkga = BrkgaMpIpr(**param_values)

        # 1st initialization.
        brkga.initialize()
        with self.assertRaises(RuntimeError) as context:
            # 2nd initialization.
            brkga.initialize()
        self.assertEqual(
            str(context.exception).strip(),
            "The algorithm is already initialized. "
            "Please call 'reset()' instead.")

        # Custom function is not defined.
        filename = os.path.join(CONFIG_DIR, "custom_bias_function.conf")
        brkga_params, _ = load_configuration(filename)

        param_values = deepcopy(self.default_param_values)
        param_values["params"] = brkga_params
        brkga = BrkgaMpIpr(**param_values)

        with self.assertRaises(ValueError) as context:
            brkga.initialize()
        self.assertEqual(
            str(context.exception).strip(),
            "The bias function is not defined. Call "
            "set_bias_custom_function() before call initialize().")

        ########################
        # Test without warmstart
        ########################

        param_values = deepcopy(self.default_param_values)
        param_values["sense"] = Sense.MAXIMIZE
        params = param_values["params"]
        brkga = BrkgaMpIpr(**param_values)
        brkga.initialize()

        self.assertTrue(brkga._initialized,
                        "Flag 'brkga._initialized' is supposed to be 'True'")
        self.assertFalse(
            brkga._reset_phase,
            "Flag 'brkga._reset_phase' is supposed to be 'False'")

        self.assertEqual(len(brkga._current_populations),
                         params.num_independent_populations)
        self.assertEqual(len(brkga._previous_populations),
                         params.num_independent_populations)

        for i in range(params.num_independent_populations):
            self.assertEqual(len(brkga._current_populations[i].chromosomes),
                             params.population_size)
            self.assertEqual(len(brkga._current_populations[i].fitness),
                             params.population_size)
            self.assertEqual(len(brkga._previous_populations[i].chromosomes),
                             params.population_size)
            self.assertEqual(len(brkga._previous_populations[i].fitness),
                             params.population_size)

            self.assertEqual(brkga._current_populations[i].chromosomes,
                             brkga._previous_populations[i].chromosomes)

            self.assertIsNot(brkga._current_populations[i].chromosomes,
                             brkga._previous_populations[i].chromosomes)

            correct_order = True
            for j in range(1, brkga.params.population_size):
                correct_order &= \
                    brkga._current_populations[i].fitness[j - 1][0] >= \
                    brkga._current_populations[i].fitness[j][0]
            # end for
            self.assertTrue(correct_order, "incorrect chromosome order")
        # end for

        param_values = deepcopy(self.default_param_values)
        param_values["sense"] = Sense.MINIMIZE
        params = param_values["params"]
        brkga = BrkgaMpIpr(**param_values)
        brkga.initialize()

        for i in range(params.num_independent_populations):
            correct_order = True
            for j in range(1, brkga.params.population_size):
                correct_order &= \
                    brkga._current_populations[i].fitness[j - 1][0] <= \
                    brkga._current_populations[i].fitness[j][0]
            # end for
            self.assertTrue(correct_order, "incorrect chromosome order")
        # end for

        ########################
        # Test with warmstart
        ########################

        local_rng = Random(param_values["seed"])
        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ])
        ]

        param_values = deepcopy(self.default_param_values)
        param_values["sense"] = Sense.MINIMIZE
        params = param_values["params"]
        brkga = BrkgaMpIpr(**param_values)
        brkga.set_initial_population(chromosomes)
        brkga.initialize()

        for i in range(params.num_independent_populations):
            self.assertEqual(len(brkga._current_populations[i].chromosomes),
                             params.population_size)
            self.assertEqual(len(brkga._current_populations[i].fitness),
                             params.population_size)
            self.assertEqual(len(brkga._previous_populations[i].chromosomes),
                             params.population_size)
            self.assertEqual(len(brkga._previous_populations[i].fitness),
                             params.population_size)

            self.assertEqual(brkga._current_populations[i].chromosomes,
                             brkga._previous_populations[i].chromosomes)

            self.assertIsNot(brkga._current_populations[i].chromosomes,
                             brkga._previous_populations[i].chromosomes)
        # end for

        old_chr = deepcopy(chromosomes[0])
        param_values["decoder"].decode(chromosomes[0], rewrite=True)
        self.assertNotEqual(chromosomes[0], old_chr)
        self.assertEqual(brkga._current_populations[0].chromosomes[0],
                         chromosomes[0])

        # Create a local chromosome and applied the decoder on it.
        local_rng = Random(param_values["seed"])
        for _ in range(1000):
            local_rng.random()
        local_chr = BaseChromosome([
            local_rng.random() for _ in range(param_values["chromosome_size"])
        ])
        param_values["decoder"].decode(local_chr, rewrite=True)

        # 4th chromosome must be the 1st generated one due to the warmstart.
        self.assertEqual(brkga._current_populations[0].chromosomes[3],
                         local_chr)

        ########################
        # Test reset phase
        ########################

        param_values = deepcopy(self.default_param_values)
        params = param_values["params"]
        brkga = BrkgaMpIpr(**param_values)
        brkga.initialize()

        # Create a local RNG and advance it until the same state as the
        # internal BRKGA RNG after initialization.
        local_rng = Random(param_values["seed"])
        skip = 1000 + params.num_independent_populations * \
               params.population_size * brkga.chromosome_size
        for _ in range(skip):
            local_rng.random()

        self.assertEqual(brkga._rng.getstate(), local_rng.getstate())

        brkga._reset_phase = True
        brkga.initialize()

        # Create a local chromosome and applied the decoder on it.
        local_chr = BaseChromosome([
            local_rng.random() for _ in range(param_values["chromosome_size"])
        ])
        param_values["decoder"].decode(local_chr, rewrite=True)

        self.assertEqual(brkga._current_populations[0].chromosomes[0],
                         local_chr)
Exemplo n.º 2
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}")
Exemplo n.º 3
0
    def test_set_initial_population(self):
        """
        Tests set_initial_population() method.
        """

        param_values = deepcopy(self.default_param_values)
        param_values["chromosome_size"] = 3
        param_values["params"].num_independent_populations = 2
        brkga = BrkgaMpIpr(**param_values)

        local_rng = Random(param_values["seed"])

        chromosomes = [
            BaseChromosome() for _ in range(brkga.params.population_size + 1)
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Number of given chromosomes (11) is large than "
            "the population size (10)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"] + 1)
            ])
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Error on setting initial population: chromosome 0 "
            "does not have the required dimension "
            "(actual size: 4, required size: 3)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"] - 1)
            ])
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Error on setting initial population: chromosome 0 "
            "does not have the required dimension "
            "(actual size: 2, required size: 3)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"] + 1)
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ])
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Error on setting initial population: chromosome 0 "
            "does not have the required dimension "
            "(actual size: 4, required size: 3)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"] + 1)
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ])
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Error on setting initial population: chromosome 1 "
            "does not have the required dimension "
            "(actual size: 4, required size: 3)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"] + 1)
            ])
        ]
        with self.assertRaises(ValueError) as context:
            brkga.set_initial_population(chromosomes)
        self.assertEqual(
            str(context.exception).strip(),
            "Error on setting initial population: chromosome 2 "
            "does not have the required dimension "
            "(actual size: 4, required size: 3)")

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ])
        ]
        brkga.set_initial_population(chromosomes)

        self.assertEqual(brkga._current_populations[0].chromosomes[0],
                         chromosomes[0])
        self.assertIsNot(brkga._current_populations[0].chromosomes[0],
                         chromosomes[0])

        chromosomes[0] = BaseChromosome([0.1111, 0.2222, 0.3333])
        self.assertNotEqual(brkga._current_populations[0].chromosomes[0],
                            chromosomes[0])

        chromosomes = [
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ]),
            BaseChromosome([
                local_rng.random()
                for _ in range(param_values["chromosome_size"])
            ])
        ]
        brkga.set_initial_population(chromosomes)

        self.assertEqual(len(brkga._current_populations[0].chromosomes),
                         len(chromosomes))
        self.assertEqual(brkga._current_populations[0].chromosomes,
                         chromosomes)
        self.assertIsNot(brkga._current_populations[0].chromosomes,
                         chromosomes)

        self.assertEqual(brkga._initial_population, True)