Esempio n. 1
0
    def update(self, space: Space, function: Function, iteration: int,
               n_iterations: int) -> None:
        """Wraps motion and genetic updates 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.

        """

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

        # Calculates the food location (eq. 12)
        food = self._food_location(space.agents, function)

        # Iterates through all agents
        for i, _ in enumerate(space.agents):
            # Updates current agent's position
            space.agents[i].position = self._update_position(
                space.agents,
                i,
                iteration,
                n_iterations,
                food,
                self.motion[i],
                self.foraging[i],
            )

            # Performs the crossover and mutation
            space.agents[i] = self._crossover(space.agents, i)
            space.agents[i] = self._mutation(space.agents, i)
Esempio n. 2
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]
Esempio n. 3
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]
Esempio n. 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]
Esempio n. 5
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
Esempio n. 6
0
    def evaluate(self, space: Space, function: Function) -> None:
        """Evaluates the search space according to the objective function.

        Args:
            space: A TreeSpace object.
            function: A Function object that will be used as the objective function.

        """

        # Iterates through all (trees, agents)
        for (tree, agent) in zip(space.trees, space.agents):
            # Runs through the tree and returns a position array
            agent.position = copy.deepcopy(tree.position)

            # Checks the agent limits
            agent.clip_by_bound()

            # Calculates the fitness value of the agent
            agent.fit = function(agent.position)

            # If tree's fitness is better than global fitness
            if agent.fit < space.best_agent.fit:
                # Makes a deep copy of current tree, position and fitness
                space.best_tree = copy.deepcopy(tree)
                space.best_agent.position = copy.deepcopy(agent.position)
                space.best_agent.fit = copy.deepcopy(agent.fit)
                space.best_agent.ts = int(time.time())
Esempio n. 7
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Lion 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.

        """

        # Gets nomad and non-nomad (pride) lions
        nomads = self._get_nomad_lions(space.agents)
        prides = self._get_pride_lions(space.agents)

        # Performs the hunting procedure, moving, roaming,
        # mating and defending for pride lions (step 3)
        self._hunting(prides, function)
        self._moving_safe_place(prides)
        self._roaming(prides, function)
        pride_cubs = self._mating(prides, function)
        nomads, prides = self._defense(nomads, prides, pride_cubs)

        # Performs roaming, mating and attacking
        # for nomad lions (step 4)
        self._nomad_roaming(nomads, function)
        nomads = self._nomad_mating(nomads, function)
        nomads, prides = self._nomad_attack(nomads, prides)

        # Migrates females lions from prides (step 5)
        nomads, prides = self._migrating(nomads, prides)

        # Equilibrates the nomads and prides population (step 6)
        nomads, prides = self._equilibrium(nomads, prides, space.n_agents)

        # Checks if there is at least one male per pride
        self._check_prides_for_males(prides)

        # Defines the correct splitting point, so
        # the agents in space can be correctly updated
        correct_nomad_size = int(self.N * space.n_agents)

        # Updates the nomads
        space.agents[:correct_nomad_size] = copy.deepcopy(
            nomads[:correct_nomad_size])

        # Updates the prides
        space.agents[correct_nomad_size:] = copy.deepcopy(
            list(itertools.chain.from_iterable(prides)))
Esempio n. 8
0
    def update(self, space: Space, function: Function, iteration: int) -> None:
        """Wraps Bat 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.
            iteration: Current iteration.

        """

        # Declares alpha constant
        alpha = 0.9

        # Iterates through all agents
        for i, agent in enumerate(space.agents):
            # Updates frequency (eq. 2)
            # Note that we have to apply (min - max) instead of (max - min) or it will not converge
            beta = rnd.generate_uniform_random_number()
            self.frequency[i] = self.f_min + (self.f_min - self.f_max) * beta

            # Updates velocity (eq. 3)
            self.velocity[i] += (agent.position -
                                 space.best_agent.position) * self.frequency[i]

            # Updates agent's position (eq. 4)
            agent.position += self.velocity[i]

            # Generates random uniform and gaussian numbers
            p = rnd.generate_uniform_random_number()
            e = rnd.generate_gaussian_random_number()

            # Checks if probability is bigger than current pulse rate
            if p > self.pulse_rate[i]:
                # Performs a local random walk (eq. 5)
                # We apply 0.001 to limit the step size
                agent.position = space.best_agent.position + 0.001 * e * np.mean(
                    self.loudness)

            # Checks agent limits
            agent.clip_by_bound()

            # Evaluates agent
            agent.fit = function(agent.position)

            # Checks if probability is smaller than loudness and if fit is better
            if p < self.loudness[i] and agent.fit < space.best_agent.fit:
                # Copies the new solution to space's best agent
                space.best_agent = copy.deepcopy(agent)

                # Increasing pulse rate (eq. 6 - left)
                self.pulse_rate[i] = self.r * (1 - np.exp(-alpha * iteration))

                # Decreasing loudness (eq. 6 - right)
                self.loudness[i] = self.A * alpha
Esempio n. 9
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]
                )
Esempio n. 10
0
    def update(self, space: Space, function: Function, n_iterations: int) -> None:
        """Wraps Water Cycle 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.
            n_iterations: Maximum number of iterations.

        """

        # Calculates the flow intensity
        self._flow_intensity(space.agents)

        # Updates every stream position
        self._update_stream(space.agents, function)

        # Updates every river position
        self._update_river(space.agents, space.best_agent, function)

        # Iterates through all rivers
        for i in range(1, self.nsr):
            # Iterates through all raindrops
            for j in range(self.nsr, len(space.agents)):
                # If raindrop position is better than river's
                if space.agents[j].fit < space.agents[i].fit:
                    # Exchanges their positions
                    space.agents[i], space.agents[j] = space.agents[j], space.agents[i]

        # Iterates through all rivers:
        for i in range(1, self.nsr):
            # If river position is better than seá's
            if space.agents[i].fit < space.agents[0].fit:
                # Exchanges their positions
                space.agents[i], space.agents[0] = space.agents[0], space.agents[i]

        # Performs the raining process (eq. 12)
        self._raining_process(space.agents, space.best_agent)

        # Updates the evaporation condition
        self.d_max -= self.d_max / n_iterations
Esempio n. 11
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
Esempio n. 12
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]
Esempio n. 13
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
Esempio n. 14
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]
Esempio n. 15
0
    def update(
        self, space: Space, function: Function, iteration: int, n_iterations: int
    ) -> None:
        """Wraps Lightning Search 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.
            iteration: Current iteration.
            n_iterations: Maximum number of iterations.

        """

        # Increases the channel's time
        self.time += 1

        # If channel has reached maximum allowed time
        if self.time >= self.max_time:
            # Sorts agents
            space.agents.sort(key=lambda x: x.fit)

            # Replaces the worst channel with the best one
            space.agents[-1] = copy.deepcopy(space.agents[0])

            # Resets the channel's time
            self.time = 0

        # Re-sorts the agents
        space.agents.sort(key=lambda x: x.fit)

        # Updates the direction
        self._update_direction(space.agents[0], function)

        # Calculates the current energy
        energy = self.E - 2 * np.exp(-5 * (n_iterations - iteration) / n_iterations)

        # Iterates through all agents
        for agent in space.agents:
            # Updates agent's position
            self._update_position(agent, space.agents[0], function, energy)
Esempio n. 16
0
    def update(self, space: Space, function: Function) -> None:
        """Wraps Electromagnetic Field Optimization over all agents and variables (eq. 1-4).

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

        """

        # Sorts agents according to their fitness
        space.agents.sort(key=lambda x: x.fit)

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

        # Making a deepcopy of current's best agent
        agent = copy.deepcopy(space.agents[0])

        # Generates a uniform random number for the force
        force = r.generate_uniform_random_number()

        # For every decision variable
        for j in range(agent.n_variables):
            # Calculates the index of positive, negative and neutral particles
            pos, neg, neu = self._calculate_indexes(n_agents)

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

            # If random number is smaller than the probability of selecting eletromagnets
            if r1 < self.ps_ratio:
                # Applies agent's position as positive particle's position
                agent.position[j] = space.agents[pos].position[j]

            # If random number is bigger
            else:
                # Calculates the new agent's position
                agent.position[j] = (space.agents[neg].position[j] +
                                     self.phi * force *
                                     (space.agents[pos].position[j] -
                                      space.agents[neu].position[j]) - force *
                                     (space.agents[neg].position[j] -
                                      space.agents[neu].position[j]))

        # Clips the agent's position to its limits
        agent.clip_by_bound()

        # Generates a third uniform random number
        r2 = r.generate_uniform_random_number()

        # If random number is smaller than probability of changing a random eletromagnet
        if r2 < self.r_ratio:
            # Update agent's position based on RI
            agent.position[self.RI] = r.generate_uniform_random_number(
                agent.lb[self.RI], agent.ub[self.RI])

            # Increases RI by one
            self.RI += 1

            # If RI exceeds the number of variables
            if self.RI >= agent.n_variables:
                # Resets it to one
                self.RI = 1

        # Calculates the agent's fitness
        agent.fit = function(agent.position)

        # If newly generated agent fitness is better than worst fitness
        if agent.fit < space.agents[-1].fit:
            # Updates the corresponding agent's object
            space.agents[-1] = copy.deepcopy(agent)
Esempio n. 17
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]