def gen_conf1():
    param_values = deepcopy(default_param_values)
    brkga_params = param_values["params"]

    brkga_params.population_size = 100
    brkga_params.elite_percentage = 0.3
    brkga_params.mutants_percentage = 0.1
    brkga_params.num_elite_parents = 1
    brkga_params.total_parents = 2
    brkga_params.bias_type = BiasFunctionType.LOGINVERSE
    brkga_params.num_independent_populations = 1
    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"] = sum_decoder
    param_values["sense"] = Sense.MAXIMIZE
    param_values["seed"] = 4013750229
    param_values["chromosome_size"] = chromosome_size
    param_values["evolutionary_mechanism_on"] = True

    print("\n> Building configuration 1")
    brkga = BrkgaMpIpr(**param_values)
    brkga.initialize()

    print("> Writing configuration 1")
    with open(os.path.join(STATE_DIR, "state1.pickle"), "wb") as hd:
        pickle.dump(brkga, hd)

    print("> Evolving population 0")

    brkga.evolve_population(0)
    fitness1 = brkga.get_best_fitness()
    chromosome1 = brkga.get_best_chromosome()

    brkga.evolve_population(0)
    fitness2 = brkga.get_best_fitness()
    chromosome2 = brkga.get_best_chromosome()

    for _ in range(100):
        brkga.evolve_population(0)
    fitness102 = brkga.get_best_fitness()
    chromosome102 = brkga.get_best_chromosome()

    with open(os.path.join(SOLUTION_DIR, "best_solution1.pickle"), "wb") as hd:
        pickle.dump(
            {
                "fitness1": fitness1,
                "chromosome1": chromosome1,
                "fitness2": fitness2,
                "chromosome2": chromosome2,
                "fitness102": fitness102,
                "chromosome102": chromosome102,
            },
            hd
        )
Example #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}")
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_get_best_fitness(self):
        """
        Tests get_best_fitness() method.
        """

        param_values = deepcopy(self.default_param_values)
        param_values["sense"] = Sense.MAXIMIZE
        param_values["seed"] = 12323
        param_values["chromosome_size"] = self.chromosome_size
        param_values["params"].population_size = 500
        param_values["params"].num_independent_populations = 3

        params = param_values["params"]
        brkga = BrkgaMpIpr(**param_values)

        # Not initialized
        with self.assertRaises(RuntimeError) as context:
            brkga.get_best_fitness()
        self.assertEqual(str(context.exception).strip(),
                         "The algorithm hasn't been initialized. "
                         "Call 'initialize()' before 'get_best_fitness()'")

        brkga.initialize()

        ########################
        # Test for maximization
        ########################

        local_rng = Random(param_values["seed"])
        for _ in range(1000):
            local_rng.random()

        num_individuals = params.population_size * \
                          params.num_independent_populations

        best_value = -math.inf
        for _ in range(num_individuals):
            local_chr = BaseChromosome([
                local_rng.random() for _ in range(param_values["chromosome_size"])
            ])
            best_value = max(
                best_value, self.sum_decoder.decode(local_chr, True)
            )

        # Assert the both generators are in the same state.
        self.assertEqual(brkga._rng.getstate(), local_rng.getstate())

        # Test the actual value.
        self.assertAlmostEqual(brkga.get_best_fitness(), best_value)

        ########################
        # Test for minimization
        ########################

        param_values["sense"] = Sense.MINIMIZE
        brkga = BrkgaMpIpr(**param_values)
        brkga.initialize()

        local_rng = Random(param_values["seed"])
        for _ in range(1000):
            local_rng.random()

        num_individuals = params.population_size * \
                          params.num_independent_populations

        best_value = math.inf
        for _ in range(num_individuals):
            local_chr = BaseChromosome([
                local_rng.random() for _ in range(param_values["chromosome_size"])
            ])
            best_value = min(
                best_value, self.sum_decoder.decode(local_chr, True)
            )

        # Assert the both generators are in the same state.
        self.assertEqual(brkga._rng.getstate(), local_rng.getstate())

        # Test the actual value.
        self.assertAlmostEqual(brkga.get_best_fitness(), best_value)
Example #5
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)
def gen_conf4():
    param_values = deepcopy(default_param_values)
    brkga_params = param_values["params"]

    chromosome_size = 500
    instance = Instance(chromosome_size)

    brkga_params.population_size = 100
    brkga_params.elite_percentage = 0.35
    brkga_params.mutants_percentage = 0.15
    brkga_params.num_elite_parents = 1
    brkga_params.total_parents = 2
    brkga_params.bias_type = BiasFunctionType.EXPONENTIAL
    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"] = 2947804214761
    param_values["chromosome_size"] = chromosome_size
    param_values["evolutionary_mechanism_on"] = True

    print("\n> Building configuration 4")
    brkga = BrkgaMpIpr(**param_values)
    brkga.initialize()

    rho = 0.75
    brkga.set_bias_custom_function(lambda x: rho if x == 1 else 1.0 - rho)

    print("> Writing configuration 4")
    with open(os.path.join(STATE_DIR, "state4.pickle"), "wb") as hd:
        pickle.dump(brkga, hd)

    print("> Evolving population 0...")
    brkga.evolve_population(0)
    fitness1 = brkga.get_best_fitness()
    chromosome1 = brkga.get_best_chromosome()

    print("> Evolving population 1...")
    brkga.evolve_population(1)
    fitness2 = brkga.get_best_fitness()
    chromosome2 = brkga.get_best_chromosome()

    print("> Evolving population 2...")
    brkga.evolve_population(2)
    fitness3 = brkga.get_best_fitness()
    chromosome3 = brkga.get_best_chromosome()

    print("> Evolving both populations for 100 generations...")
    for _ in range(100):
        start_time = time()
        brkga.evolve_population(0)
        brkga.evolve_population(1)
        brkga.evolve_population(2)
        print(f"Elapsed time: {time() - start_time :.2f}")

    fitness103 = brkga.get_best_fitness()
    chromosome103 = brkga.get_best_chromosome()

    with open(os.path.join(SOLUTION_DIR, "best_solution4.pickle"), "wb") as hd:
        pickle.dump(
            {
                "fitness1": fitness1,
                "chromosome1": chromosome1,
                "fitness2": fitness2,
                "chromosome2": chromosome2,
                "fitness3": fitness2,
                "chromosome3": chromosome2,
                "fitness103": fitness103,
                "chromosome103": chromosome103,
            },
            hd
        )
def gen_conf3():
    param_values = deepcopy(default_param_values)
    brkga_params = param_values["params"]

    chromosome_size = 500
    instance = Instance(chromosome_size)

    brkga_params.population_size = 100
    brkga_params.elite_percentage = 0.35
    brkga_params.mutants_percentage = 0.17
    brkga_params.num_elite_parents = 3
    brkga_params.total_parents = 5
    brkga_params.bias_type = BiasFunctionType.EXPONENTIAL
    brkga_params.num_independent_populations = 5
    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"] = 253624607406
    param_values["chromosome_size"] = chromosome_size
    param_values["evolutionary_mechanism_on"] = True

    print("\n> Building configuration 3")
    brkga = BrkgaMpIpr(**param_values)
    brkga.initialize()

    print("> Writing configuration 3")
    with open(os.path.join(STATE_DIR, "state3.pickle"), "wb") as hd:
        pickle.dump(brkga, hd)

    print("> Evolving both populations for one generation...")
    for i in range(brkga_params.num_independent_populations):
        brkga.evolve_population(i)
    fitness1 = brkga.get_best_fitness()
    chromosome1 = brkga.get_best_chromosome()

    print("> Evolving both populations for another generation...")
    for i in range(brkga_params.num_independent_populations):
        brkga.evolve_population(i)
    brkga.evolve_population(1)
    fitness2 = brkga.get_best_fitness()
    chromosome2 = brkga.get_best_chromosome()

    print("> Evolving both populations for 100 generations...")
    for _ in range(100):
        start_time = time()
        for i in range(brkga_params.num_independent_populations):
            brkga.evolve_population(i)
        print(f"Elapsed time: {time() - start_time :.2f}")

    fitness102 = brkga.get_best_fitness()
    chromosome102 = brkga.get_best_chromosome()

    with open(os.path.join(SOLUTION_DIR, "best_solution3.pickle"), "wb") as hd:
        pickle.dump(
            {
                "fitness1": fitness1,
                "chromosome1": chromosome1,
                "fitness2": fitness2,
                "chromosome2": chromosome2,
                "fitness102": fitness102,
                "chromosome102": chromosome102,
            },
            hd
        )

    print("fitness", fitness1)
    # print("chromosome", chromosome1)

    print("fitness", fitness2)
    # print("chromosome", chromosome2)

    print("fitness", fitness102)
def gen_conf2():
    param_values = deepcopy(default_param_values)
    brkga_params = param_values["params"]

    chromosome_size = 1000
    instance = Instance(chromosome_size)

    brkga_params.population_size = 500
    brkga_params.elite_percentage = 0.25
    brkga_params.mutants_percentage = 0.25
    brkga_params.num_elite_parents = 5
    brkga_params.total_parents = 50
    brkga_params.bias_type = BiasFunctionType.QUADRATIC
    brkga_params.num_independent_populations = 2
    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"] = RankDecode(instance)
    param_values["sense"] = Sense.MINIMIZE
    param_values["seed"] = 1297832326904308
    param_values["chromosome_size"] = chromosome_size
    param_values["evolutionary_mechanism_on"] = True

    print("\n> Building configuration 2")
    brkga = BrkgaMpIpr(**param_values)
    brkga.initialize()

    print("> Writing configuration 2")
    with open(os.path.join(STATE_DIR, "state2.pickle"), "wb") as hd:
        pickle.dump(brkga, hd)

    print("> Evolving population 0...")
    brkga.evolve_population(0)
    fitness1 = brkga.get_best_fitness()
    chromosome1 = brkga.get_best_chromosome()

    print("> Evolving population 1...")
    brkga.evolve_population(1)
    fitness2 = brkga.get_best_fitness()
    chromosome2 = brkga.get_best_chromosome()

    print("> Evolving both populations for 100 generations...")
    for _ in range(100):
        start_time = time()
        brkga.evolve_population(0)
        brkga.evolve_population(1)
        print(f"Elapsed time: {time() - start_time :.2f}")

    fitness102 = brkga.get_best_fitness()
    chromosome102 = brkga.get_best_chromosome()

    with open(os.path.join(SOLUTION_DIR, "best_solution2.pickle"), "wb") as hd:
        pickle.dump(
            {
                "fitness1": fitness1,
                "chromosome1": chromosome1,
                "fitness2": fitness2,
                "chromosome2": chromosome2,
                "fitness102": fitness102,
                "chromosome102": chromosome102,
            },
            hd
        )