Example #1
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Evolutionary Programming over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Calculates the number of agents
        n_agents = len(space.agents)

        # Creates a list for the produced children
        children = []

        # Iterates through all agents
        for i, agent in enumerate(space.agents):
            # Mutates a parent and generates a new child
            a = self._mutate_parent(agent, i, function)

            # Updates the strategy
            self._update_strategy(i, agent.lb, agent.ub)

            # Appends the mutated agent to the children
            children.append(a)

        # Joins both populations
        space.agents += children

        # Number of individuals to be selected
        n_individuals = int(n_agents * self.bout_size)

        # Creates an empty array of wins
        wins = np.zeros(len(space.agents))

        # Iterates through all agents in the new population
        for i, agent in enumerate(space.agents):
            # Iterate through all tournament individuals
            for _ in range(n_individuals):
                # Gathers a random index
                index = r.generate_integer_random_number(0, len(space.agents))

                # If current agent's fitness is smaller than selected one
                if agent.fit < space.agents[index].fit:
                    # Increases its winning by one
                    wins[i] += 1

        # Sorts agents list based on its winnings
        space.agents = [
            agents
            for _, agents in sorted(
                zip(wins, space.agents), key=lambda pair: pair[0], reverse=True
            )
        ]

        # Gathers the best `n_agents`
        space.agents = space.agents[:n_agents]
Example #2
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Evolution Strategies over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Calculates the number of agents
        n_agents = len(space.agents)

        # Creates a list for the produced children
        children = []

        # Iterate through all children
        for i in range(self.n_children):
            # Mutates a parent and generates a new child
            a = self._mutate_parent(space.agents[i], i, function)

            # Updates the strategy
            self._update_strategy(i)

            # Appends the mutated agent to the children
            children.append(a)

        # Joins both populations, sorts agents and gathers best `n_agents`
        space.agents += children
        space.agents.sort(key=lambda x: x.fit)
        space.agents = space.agents[:n_agents]
Example #3
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Forest Optimization Algorithm over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Performs the local seeding
        self._local_seeding(space, function)

        # Limits the population
        candidate = self._population_limiting(space)

        # Performs the global seeding
        self._global_seeding(space, function, candidate)

        # Sorts agents and their corresponding ages
        space.agents, self.age = map(
            list,
            zip(*sorted(zip(space.agents, self.age), key=lambda x: x[0].fit)))

        # Sets the best tree's age to zero
        self.age[0] = 0
Example #4
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Artificial Flora over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Sorts the agents
        space.agents.sort(key=lambda x: x.fit)

        # Creates a list of new agents
        new_agents = []

        # Iterates thorugh all agents
        for i, agent in enumerate(space.agents):
            # Iterates through amount of branches
            for _ in range(self.m):
                # Makes a copy of current agent
                a = copy.deepcopy(agent)

                # Generates random numbers
                r1 = r.generate_uniform_random_number()
                r2 = r.generate_uniform_random_number()
                r3 = r.generate_uniform_random_number()

                # Calculates the new distance (eq. 1)
                distance = (self.g_distance[i] * r1 * self.c1 +
                            self.p_distance[i] * r2 * self.c2)

                # Generates a random gaussian number
                D = r.generate_gaussian_random_number(
                    0, distance, (space.n_variables, space.n_dimensions))

                # Updates offspring's position (eq. 5)
                a.position += D

                # Clips its limits
                a.clip_by_bound()

                # Evaluates its fitness
                a.fit = function(a.position)

                # Calculates the probability of selection (eq. 6)
                p = np.fabs(np.sqrt(a.fit / space.agents[-1].fit)) * self.Q

                # If random number is smaller than probability of selection
                if r3 < p:
                    # Appends the offsprings
                    new_agents.append(a)

            # Updates both grandparent and parent distances (eq. 2 and 3)
            self.g_distance[i] = self.p_distance[i]
            self.p_distance[i] = np.std(agent.position - a.position)

        # Randomly selects the agents
        idx = d.generate_choice_distribution(len(new_agents), None,
                                             space.n_agents)
        space.agents = [new_agents[i] for i in idx]
Example #5
0
    def update(self, space: Space, iteration: int, n_iterations: int) -> None:
        """Wraps Thermal Exchange Optimization over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            iteration: Current iteration.
            n_iterations: Maximum number of iterations.

        """

        # Sorts agents
        space.agents.sort(key=lambda x: x.fit)

        # Updates the thermal memory and cuts it to maximum allowed size
        self.TM.append(copy.deepcopy(space.agents[0]))
        self.TM = self.TM[-self.n_TM :]

        # Replaces the worst agents with the thermal memory and re-sorts the agents
        space.agents = space.agents[: -len(self.TM)] + self.TM
        space.agents.sort(key=lambda x: x.fit)

        # Calculates the time (eq. 9)
        time = iteration / n_iterations

        # Iterates through all environmental-based agents
        for env in self.environment:
            # Updates the environment's position (eq. 10)
            r1 = r.generate_uniform_random_number()
            env.position = 1 - (self.c1 + self.c2 * (1 - time)) * r1 * env.position

        # Iterates through both populations' agents
        for agent, env in zip(space.agents, self.environment):
            # Calculates the agent's beta value (eq. 8)
            beta = agent.fit / space.agents[-1].fit

            # Updates the agent's position (eq. 11)
            agent.position = env.position + (agent.position - env.position) * np.exp(
                -beta * time
            )

            # Generates a random number
            r1 = r.generate_uniform_random_number()

            # If random number is smaller than `pro`
            if r1 < self.pro:
                # Selects a random dimension
                idx = r.generate_integer_random_number(high=agent.n_variables)

                # Resets its position (eq. 12)
                r2 = r.generate_uniform_random_number()
                agent.position[idx] = agent.lb[idx] + r2 * (
                    agent.ub[idx] - agent.lb[idx]
                )
Example #6
0
    def _population_limiting(self, space: Space) -> List[Agent]:
        """Limits the population by removing old trees.

        Args:
            space: A Space object containing meta-information.

        Returns:
            (List[Agent]): A list of candidate trees that were removed from the forest.

        """

        # List of candidate trees
        candidate = []

        # Iterates through all agents
        for i, _ in enumerate(space.agents):
            # Checks whether current agent has exceed its life time
            if self.age[i] > self.life_time:
                # Removes the tree and its corresponding age from forest
                agent = space.agents.pop(i)
                self.age.pop(i)

                # Adds the removed agent to the candidate list
                candidate.append(agent)

        # Sorts agents and their corresponding ages
        space.agents, self.age = map(
            list,
            zip(*sorted(zip(space.agents, self.age), key=lambda x: x[0].fit)))

        # If the population exceeds the forest limits
        if len(space.agents) > self.area_limit:
            # Adds extra trees to the candidate list
            candidate += space.agents[self.area_limit:]

            # Removes the extra trees and their corresponding ages from forest
            space.agents = space.agents[:self.area_limit]
            self.age = self.age[:self.area_limit]

        return candidate
Example #7
0
    def update(self, space: Space, function: Function, iteration: int,
               n_iterations: int) -> None:
        """Wraps Invasive Weed Optimization over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.
            iteration: Current iteration.
            n_iterations: Maximum number of iterations.

        """

        # Calculates the current Spatial Dispersal
        self._spatial_dispersal(iteration, n_iterations)

        # Calculates the number of agents and creates list of offsprings
        n_agents = len(space.agents)
        offsprings = []

        # Sorts agents
        space.agents.sort(key=lambda x: x.fit)

        # Iterates through all agents
        for agent in space.agents:
            # Calculates the seeding ratio based on its fitness
            ratio = (agent.fit - space.agents[-1].fit) / (
                space.agents[0].fit - space.agents[-1].fit + c.EPSILON)

            # Calculates the number of produced seeds
            n_seeds = int(self.min_seeds +
                          (self.max_seeds - self.min_seeds) * ratio)

            # For every seed
            for _ in range(n_seeds):
                # Reproduces and flowers the seed into a new agent
                a = self._produce_offspring(agent, function)

                # Appends the agent to the offsprings
                offsprings.append(a)

        # Joins both populations, sorts and gathers best `n_agents`
        space.agents += offsprings
        space.agents.sort(key=lambda x: x.fit)
        space.agents = space.agents[:n_agents]
Example #8
0
    def compile(self, space: Space) -> None:
        """Compiles additional information that is used by this optimizer.

        Args:
            space: A Space object containing meta-information.

        """

        # Replaces the current agents with a derived Lion structure
        space.agents = [
            Lion(
                agent.n_variables,
                agent.n_dimensions,
                agent.lb,
                agent.ub,
                agent.position,
                agent.fit,
            ) for agent in space.agents
        ]

        # Calculates the number of nomad lions and their genders
        n_nomad = int(self.N * space.n_agents)
        nomad_gender = d.generate_bernoulli_distribution(1 - self.S, n_nomad)

        # Iterates through all possible nomads
        for i, agent in enumerate(space.agents[:n_nomad]):
            # Toggles to `True` the nomad property
            agent.nomad = True

            # Defines the gender according to Bernoulli distribution
            agent.female = bool(nomad_gender[i])

        # Calculates the gender of pride lions
        pride_gender = d.generate_bernoulli_distribution(
            self.S, space.n_agents - n_nomad)

        # Iterates through all possible prides
        for i, agent in enumerate(space.agents[n_nomad:]):
            # Defines the gender according to Bernoulli distribution
            agent.female = bool(pride_gender[i])

            # Allocates to the corresponding pride
            agent.pride = i % self.P
Example #9
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Genetic Algorithm over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Creates a list to hold the new population
        new_agents = []

        # Retrieves the number of agents
        n_agents = len(space.agents)

        # Calculates a list of fitness from every agent
        fitness = [agent.fit + c.EPSILON for agent in space.agents]

        # Selects the parents
        selected = self._roulette_selection(n_agents, fitness)

        # For every pair of selected parents
        for s in g.n_wise(selected):
            # Performs the crossover and mutation
            alpha, beta = self._crossover(space.agents[s[0]],
                                          space.agents[s[1]])
            alpha, beta = self._mutation(alpha, beta)

            # Checking `alpha` and `beta` limits
            alpha.clip_by_bound()
            beta.clip_by_bound()

            # Calculates new fitness for `alpha` and `beta`
            alpha.fit = function(alpha.position)
            beta.fit = function(beta.position)

            # Appends the mutated agents to the children
            new_agents.extend([alpha, beta])

        # Joins both populations, sort agents and gathers best `n_agents`
        space.agents += new_agents
        space.agents.sort(key=lambda x: x.fit)
        space.agents = space.agents[:n_agents]
Example #10
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Black Widow Optimization over all agents and variables.

        Args:
            space: Space containing agents and update-related information.
            function: A Function object that will be used as the objective function.

        """

        # Retrieves the number of agents
        n_agents = len(space.agents)
        n_variables = space.n_variables

        # Calculates the number agents that reproduces, are cannibals and mutates
        n_reproduct = int(n_agents * self.pp)
        n_cannibals = int(n_agents * self.cr)
        n_mutate = int(n_agents * self.pm)

        # Sorts agents
        space.agents.sort(key=lambda x: x.fit)

        # Selecting the best solutions and saving in auxiliary population
        agents1 = copy.deepcopy(space.agents[:n_reproduct])

        # Creates an empty auxiliary population
        agents2 = []

        # For every possible reproducting agent
        for _ in range(0, n_reproduct):
            # Sampling random uniform integers as indexes
            idx = r.generate_uniform_random_number(0, n_agents, size=2)

            # Making a deepcopy of father and mother
            father, mother = copy.deepcopy(space.agents[int(
                idx[0])]), copy.deepcopy(space.agents[int(idx[1])])

            # Creates an empty list of auxiliary agents
            new_agents = []

            # For every possible pair of variables
            for _ in range(0, int(n_variables / 2)):
                # Procreates parents into two new offsprings
                y1, y2 = self._procreating(father, mother)

                # Checks `y1` and `y2` limits
                y1.clip_by_bound()
                y2.clip_by_bound()

                # Calculates new fitness for `y1` and `y2`
                y1.fit = function(y1.position)
                y2.fit = function(y2.position)

                # Appends the mother and mutated agents to the new population
                new_agents.extend([mother, y1, y2])

            # Sorts new population
            new_agents.sort(key=lambda x: x.fit)

            # Extending auxiliary population with the number of cannibals (s. 3.3)
            agents2.extend(new_agents[:n_cannibals])

        # For every possible mutating agent
        for _ in range(0, n_mutate):
            # Sampling a random integer as index
            idx = int(r.generate_uniform_random_number(0, n_reproduct))

            # Performs the mutation
            alpha = self._mutation(agents1[idx])

            # Checks `alpha` limits
            alpha.clip_by_bound()

            # Calculates new fitness for `alpha`
            alpha.fit = function(alpha.position)

            # Appends the mutated agent to the auxiliary population
            agents2.extend([alpha])

        # Joins both populations, sorts them and retrieves `n_agents`
        space.agents += agents2
        space.agents.sort(key=lambda x: x.fit)
        space.agents = space.agents[:n_agents]