Esempio n. 1
0
    def _mutation(self, space: TreeSpace) -> None:
        """Mutates a number of individuals pre-selected through a tournament procedure.

        Args:
            space: A TreeSpace object.

        """

        # Calculates a list of current trees' fitness
        fitness = [agent.fit for agent in space.agents]

        # Number of individuals to be mutated
        n_individuals = int(space.n_agents * self.p_mutation)

        # Gathers a list of selected individuals to be replaced
        selected = g.tournament_selection(fitness, n_individuals)

        # For every selected individual
        for s in selected:
            # Gathers individual number of nodes
            n_nodes = space.trees[s].n_nodes

            # Checks if the tree has more than one node
            if n_nodes > 1:
                # Prunes the amount of maximum nodes
                max_nodes = self._prune_nodes(n_nodes)

                # Mutatets the individual
                space.trees[s] = self._mutate(space, space.trees[s], max_nodes)

            # If there is only one node
            else:
                # Re-create it with a random tree
                space.trees[s] = space.grow(space.min_depth, space.max_depth)
Esempio n. 2
0
    def _reproduction(self, space: TreeSpace) -> None:
        """Reproducts a number of individuals pre-selected through a tournament procedure (p. 99).

        Args:
            space: A TreeSpace object.

        """

        # Calculates a list of current trees' fitness
        fitness = [agent.fit for agent in space.agents]

        # Number of individuals to be reproducted
        n_individuals = int(space.n_agents * self.p_reproduction)

        # Gathers a list of selected individuals to be replaced
        selected = g.tournament_selection(fitness, n_individuals)

        # For every selected individual
        for s in selected:
            # Gathers the worst individual index
            worst = np.argmax(fitness)

            # Replace the individual by performing a deep copy on selected tree
            space.trees[worst] = copy.deepcopy(space.trees[s])

            # We also need to copy the agent
            space.agents[worst] = copy.deepcopy(space.agents[s])

            # Replaces the worst individual fitness with a minimum value
            fitness[worst] = 0
Esempio n. 3
0
    def _mutate(self, space: TreeSpace, tree: Node, max_nodes: int) -> Node:
        """Actually performs the mutation on a single tree (p. 105).

        Args:
            space: A TreeSpace object.
            trees: A Node instance to be mutated.
            max_nodes: Maximum number of nodes to be searched.

        Returns:
            (Node): A mutated tree.

        """

        # Deep copying a new mutated tree from initial tree
        mutated_tree = copy.deepcopy(tree)

        # Calculates mutation point
        mutation_point = int(r.generate_uniform_random_number(2, max_nodes))

        # Finds the node at desired mutation point
        sub_tree, flag = mutated_tree.find_node(mutation_point)

        # If the mutation point's parent is not a root (this may happen when the mutation point is a function),
        # and find_node() stops at a terminal node whose father is a root
        if sub_tree:
            # Creates a new random sub-tree
            branch = space.grow(space.min_depth, space.max_depth)

            # Checks if sub-tree should be positioned in the left
            if flag:
                # The left child will receive the sub-branch
                sub_tree.left = branch

                # And its flag will be True
                branch.flag = True

            # If `flag` is False
            else:
                # The right child will receive the sub-branch
                sub_tree.right = branch

                # And its flag will be False
                branch.flag = False

            # Connects the sub-branch to its parent
            branch.parent = sub_tree

        # Otherwise, if condition is false
        else:
            # The mutated tree will be a random tree
            mutated_tree = space.grow(space.min_depth, space.max_depth)

        return mutated_tree
Esempio n. 4
0
def optimize_gp(target, n_trees, n_terminals, n_variables, n_iterations,
                min_depth, max_depth, functions, lb, ub, hyperparams):
    """Abstracts Opytimizer's Genetic Programming into a single method.

    Args:
        target (callable): The method to be optimized.
        n_trees (int): Number of agents.
        n_terminals (int): Number of terminals
        n_variables (int): Number of variables.
        n_iterations (int): Number of iterations.
        min_depth (int): Minimum depth of trees.
        max_depth (int): Maximum depth of trees.
        functions (list): Functions' nodes.
        lb (list): List of lower bounds.
        ub (list): List of upper bounds.
        hyperparams (dict): Dictionary of hyperparameters.

    Returns:
        A History object containing all optimization's information.

    """

    # Creating the TreeSpace
    space = TreeSpace(n_trees=n_trees,
                      n_terminals=n_terminals,
                      n_variables=n_variables,
                      n_iterations=n_iterations,
                      min_depth=min_depth,
                      max_depth=max_depth,
                      functions=functions,
                      lower_bound=lb,
                      upper_bound=ub)

    # Creating the Function
    function = Function(pointer=target)

    # Creating GP's optimizer
    optimizer = GP(hyperparams=hyperparams)

    # Creating the optimization task
    task = Opytimizer(space=space, optimizer=optimizer, function=function)

    return task.start(store_best_only=True)
Esempio n. 5
0
    def _crossover(self, space: TreeSpace) -> None:
        """Crossover a number of individuals pre-selected through a tournament procedure (p. 101).

        Args:
            space: A TreeSpace object.

        """

        # Calculates a list of current trees' fitness
        fitness = [agent.fit for agent in space.agents]

        # Number of individuals to be crossovered
        n_individuals = int(space.n_agents * self.p_crossover)

        # Checks if `n_individuals` is an odd number
        if n_individuals % 2 != 0:
            # If it is, increase it by one
            n_individuals += 1

        # Gathers a list of selected individuals to be replaced
        selected = g.tournament_selection(fitness, n_individuals)

        # For every pair in selected individuals
        for s in g.n_wise(selected):
            # Calculates the amount of father and mother nodes
            father_nodes = space.trees[s[0]].n_nodes
            mother_nodes = space.trees[s[1]].n_nodes

            # Checks if both trees have more than one node
            if (father_nodes > 1) and (mother_nodes > 1):
                # Prunning father and mother nodes
                max_f_nodes = self._prune_nodes(father_nodes)
                max_m_nodes = self._prune_nodes(mother_nodes)

                # Apply the crossover operation
                space.trees[s[0]], space.trees[s[1]] = self._cross(
                    space.trees[s[0]], space.trees[s[1]], max_f_nodes, max_m_nodes
                )
Esempio n. 6
0
max_depth = 5

# Function nodes
func_nodes = ["SUM", "SUB", "MUL", "DIV"]

# Also defines the corresponding lower and upper bounds
# Note that they have to be the same size as `n_variables`
lower_bound = [0.1, 0.3, 0.5, 0.7, 0.9]
upper_bound = [0.2, 0.4, 0.6, 0.8, 1.0]

# Creates the TreeSpace
s = TreeSpace(
    n_agents,
    n_variables,
    lower_bound,
    upper_bound,
    n_terminals,
    min_depth,
    max_depth,
    func_nodes,
)

# Prints out some properties
print(s.trees[0])
print(f"Position: {s.trees[0].position}")
print(f"\nPre Order: {s.trees[0].pre_order}")
print(f"\nPost Order: {s.trees[0].post_order}")
print(
    f"\nNodes: {s.trees[0].n_nodes} | Leaves: {s.trees[0].n_leaves} | "
    f"Minimum Depth: {s.trees[0].min_depth} | Maximum Depth: {s.trees[0].max_depth}"
)
max_depth = 5

# List of functions nodes
functions = ['SUM', 'MUL', 'DIV']

# Finally, we define the lower and upper bounds
# Note that they have to be the same size as n_variables
lower_bound = [-10, -10]
upper_bound = [10, 10]

# Creating the TreeSpace object
s = TreeSpace(n_trees=n_trees,
              n_terminals=n_terminals,
              n_variables=n_variables,
              n_iterations=n_iterations,
              min_depth=min_depth,
              max_depth=max_depth,
              functions=functions,
              lower_bound=lower_bound,
              upper_bound=upper_bound)

# Hyperparameters for the optimizer
hyperparams = {
    'p_reproduction': 0.25,
    'p_mutation': 0.1,
    'p_crossover': 0.2,
    'prunning_ratio': 0.0
}

# Creating GP's optimizer
p = GP(hyperparams=hyperparams)